package com.opc.Service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.opc.Common.MessageConstant;
import com.opc.Config.CacheUtil;
import com.opc.Mapper.*;
import com.opc.Pojo.*;
import com.opc.Service.AsyncMessage;
import com.opc.Service.CarService;
import com.opc.Service.JSerialCommIOService;
import com.opc.Service.OpcUaService;
import com.opc.properties.CarNodeProperties;
import com.opc.properties.CarTypeProperties;
import com.opc.properties.FrequencyProperties;
import com.opc.properties.IpProperties;
import com.opc.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.nodes.UaNode;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class OpcUaServiceImpl implements OpcUaService {

    @Autowired
    private AllowPlusMapper allowPlusMapper;
    @Autowired
    private CarNodeProperties carNodeProperties;
    @Autowired
    private ScrewMapper screwMapper;
    @Autowired
    private CarNumPrefixMapper carNumPrefixMapper;
    @Autowired
    //@Qualifier("jSerialCommIOService")
    private JSerialCommIOService jSerialCommIOService;
    @Autowired
    private WebSocketServer webSocketServer;
    @Autowired
    private CarService carService;
    @Autowired
    private CarMapper carMapper;
    @Autowired
    private IpProperties ipProperties;
    @Autowired
    private CarTypeProperties carTypeProperties;
    @Autowired
    private FrequencyProperties frequencyProperties;
    @Autowired
    private Scheduler scheduler;
    @Autowired
    private OpcUaService opcUaService;
    @Autowired
    private ScrewTypeMapper screwTypeMapper;
    @Autowired
    private CarStatusMapper carStatusMapper;
    @Autowired
    private AsyncMessage asyncMessage;
    @Autowired
    private TorqueStandardsMapper torqueStandardsMapper;
    
    public static String formatToYYMMDD(String todayStr) {
        if (todayStr == null || todayStr.length() != 10) {
            log.info("yyyy-MM-dd格式不正确");
//            throw new IllegalArgumentException("Input string must be in yyyy-MM-dd format");
        }
        // 截取年份的后两位
        String year = null;
        if (todayStr != null) {
            year = todayStr.substring(2, 4);
        }
        // 截取月份
        String month = null;
        if (todayStr != null) {
            month = todayStr.substring(5, 7);
        }
        // 截取日期
        String day = null;
        if (todayStr != null) {
            day = todayStr.substring(8, 10);
        }
//        if (day.startsWith("0")) {
//            day = day.substring(1);
//        }
        // 组合成 yyMMdd 格式
        return year + month + day;
    }


    /**
     *Administrator
     * 创建OPC UA客户端
     * @return
     * @throws Exception
     */
    @Override
    //@Suspendable
    //如果createClient方法中包含可能阻塞的操作，
    // 并且您希望这些操作在协程中执行，以避免阻塞整个线程，
    // 那么加上@Suspendable注解是有意义的。
    public OpcUaClient createClient() throws ExecutionException, InterruptedException {
        OpcUaClient client = null;
//        log.info("创建客户端"+client);
        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        try {
            Files.createDirectories(securityTempDir);
        } catch (IOException e) {
            log.info("创建文件异常");
            log.info(e.getMessage());
            e.printStackTrace();
//            throw new RuntimeException(e);
        }
        log.info("连接到的节点是"+ipProperties.getEndPointUrl());
        if (!Files.exists(securityTempDir)) {
            log.info("文件不存在");
            try {
                log.info("无法创建安全目录dir:");
            } catch (Exception e) {
//                log.info("RuntimeException");
                log.info(e.getMessage());
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
        }
        int retryCount = 0;
        int maxRetry = 8;
        long waitTime = 1500; // 初始等待时间设置为1500毫秒
        long MAX_WAIT_TIME = 6000;

        while (true){ // 无限循环，直到连接成功
            // 清理之前创建的所有节点
//            clearExistingNodes();
//            OpcUaClient client = null;
//            log.info("重建节点。。。");
//            //等待释放资源
//            try {
//                Thread.sleep(MAX_WAIT_TIME);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            try {
                log.info("重建节点。。。");
                //// 如果客户端创建成功，返回客户端实例，就会结束循环
                client = OpcUaClient.create(ipProperties.getEndPointUrl(),
                        //过滤可用的端点。
                        // 它从服务器返回的端点列表中查找第一个安全策略为 None 的端点。
                        // 这意味着这个客户端将使用不带安全性的连接方式。
                        endpoints ->
                                endpoints.stream()
                                        .filter(e -> //不带安全性的连接（SecurityPolicy.None）
                                                e.getSecurityPolicyUri()
                                                        .equals(SecurityPolicy.None.getUri()))
                                        .findFirst(),
                        configBuilder ->
                                configBuilder
                                        .setApplicationName(LocalizedText.english
                                                ("eclipse milo opc-ua client"))
                                        //设置应用程序的 URI，通常用于标识客户端。
                                        .setApplicationUri("urn:eclipse:milo:examples:client")
                                        //设置身份提供者为 AnonymousProvider，
                                        // 这意味着客户端将以匿名身份连接到服务器，不需要身份验证。
                                        .setIdentityProvider(new AnonymousProvider())
                                        //设置请求超时时间为 500 毫秒。
                                        .setRequestTimeout(UInteger.valueOf(frequencyProperties.getNodeRequestTimeout()))
                                        .build()
                );
//                log.info("client是"+client);
                return client;
            } catch (UaException e) {
                log.info("创建客户端异常");
//                if (client != null) {
//                    try {
//                        // 尝试关闭客户端以释放资源
//                        client.disconnect().get(); // 等待异步操作完成
//                    } catch (InterruptedException | ExecutionException e1) {
//                        e1.printStackTrace();
//                    }
//                }
                Map map0 = new HashMap<>();
                map0.put("car1Num", "PLC未连接");
                map0.put("car1Type", "PLC未连接");
                map0.put("repeat1",  "PLC未连接");
                map0.put("car2Num", "PLC未连接");
                map0.put("car2Type", "PLC未连接");
                map0.put("repeat2", "PLC未连接");
                String json0 = JSON.toJSONString(map0);
                webSocketServer.sendToAllClient(json0);
//                waitTime = Math.min(waitTime + 500, MAX_WAIT_TIME);
//                asyncMessage.sendTest(waitTime, MAX_WAIT_TIME);
                try {
                    // 退避策略：每次重试后等待时间加倍，直到达到某个最大值
                    waitTime = Math.min(waitTime + 500, MAX_WAIT_TIME);
//在协程中使用 Thread.sleep(waitTime); 是可以的，但这样做会阻塞当前线程，
// 而不是仅仅挂起当前协程。
                    Thread.sleep(waitTime);
                    // 挂起当前协程一段时间后重试
//                    Strand.sleep(waitTime);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }//释放
//                catch (SuspendExecution ex) {
//                    throw new RuntimeException(ex);
//                }

//                if (retryCount < maxRetry) {
//                    log.info("重连次数内"+retryCount);
//                    retryCount ++;
//                    Map map = new HashMap<>();
//                    map.put("message", "..创建OPC客户端失败，重连次数内..");
//                    String json = JSON.toJSONString(map);
//                    webSocketServer.sendToAllClient(json);
////                    createClient();
//                }else {
                    log.info("重试次数达到上限，停止重试");
                    Map map = new HashMap<>();
                    map.put("message", "..创建OPC客户端失败，请重启软件..");
                    String json = JSON.toJSONString(map);
                    webSocketServer.sendToAllClient(json);
                    log.info(e.getMessage());
                    e.printStackTrace();
//                    throw new RuntimeException(e);
//                }

                //用无限循环代替递归，递归可能会导致栈溢出，而循环不会占用调用栈
//                retrySubscribe();
//            } else {
//                log.info("重试次数达到上限，停止重试");
//            }
                //throw new RuntimeException(e);
            } finally {
                if (client != null) {
                    client.disconnect().get(); // 确保客户端断开连接
                }
            }
//            return null;
        }//while
    }

//    @Async
//    public void sendTest() {
//        try {
//            // 退避策略：每次重试后等待时间加倍，直到达到某个最大值
//            waitTime = Math.min(waitTime + 500, MAX_WAIT_TIME);
//            Thread.sleep(waitTime);
//        } catch (InterruptedException e1) {
//            e1.printStackTrace();
//        }
//        Map map = new HashMap<>();
//        map.put("message", "..创建OPC客户端失败，重试..");
//        String json = JSON.toJSONString(map);
//        webSocketServer.sendToAllClient(json);
//    }


    @Override
    public String[] browseNode(OpcUaClient client, UaNode uaNode) {
        List<? extends UaNode> nodes = null;
//        log.info("nodes0是"+nodes);
//        while (nodes == null) {
            // 如果为 null，默认浏览对象文件夹
            if (uaNode == null) {
                try {
                    nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);
//                    log.info("nodes2是"+nodes);
                } catch (UaException e) {
                    log.info("创建客户端异常1");
                    retrySubscribe();
                    log.info(e.getMessage());
                    e.printStackTrace();
//                    throw new RuntimeException(e);
                }
            } else {
                // 浏览指定节点的子节点
                try {
                    //TODO 处理网线断了抛出的异常
                    // Failed to create Node from Reference to ExpandedNodeId{ns=2, id=111.222.carNum1, serverIndex=0}
                    nodes = client.getAddressSpace().browseNodes(uaNode);
//                    log.info("nodes2是"+nodes);
                } catch (UaException e) {
                    log.info("创建客户端异常2");
                    log.info(e.getMessage());
                    e.printStackTrace();
//                    throw new RuntimeException(e);
                }
            }
//        }
        // 用于存储 NodeId 的列表
        List<String> nodeIds = new ArrayList<>();

        // 遍历从浏览中得到的节点列表
        for (UaNode nd : nodes) {
            // 跳过系统性节点（名称以 "_" 开头）
            String browseName = nd.getBrowseName().getName();
            String nodeIdString = nd.getNodeId().toString(); // 获取节点 ID 的字符串表示
            if (browseName.startsWith("_") || browseName.contains("示例")
                    || browseName.contains("通道") || nodeIdString.contains("ns=0")) {
                continue;
            }
//             检查节点是否有有效的 ID
            if (nd.getNodeId() != null) {
//                log.info("节点ID: " + nd.getNodeId()); // 打印节点ID
                nodeIds.add(nd.getNodeId().toString()); // 将 NodeId 添加到列表中
            }

            // 递归调用，浏览当前节点的子节点
//            log.info("递归调用");
            String[] childNodeIds = browseNode(client, nd);
            if(childNodeIds != null && childNodeIds.length > 0){
//                log.info("childNodeIds2是："+ Arrays.toString(childNodeIds));
                Collections.addAll(nodeIds, childNodeIds); // 添加子节点 ID
            }
        }
        // 将 List 转换为数组并返回
        return nodeIds.toArray(new String[0]);
    }

    //retrySubscribe 方法被声明为 synchronized，确保在多线程环境中，
    // 只有一个线程可以执行这个方法，避免竞态条件。synchronized
    //@Suspendable//可以让该方法在协程中暂停和恢复执行。这样可以简化异步编程，
    // 提高代码的可读性和可维护性，并优化资源使用
    //@Async//("asyncExecutor")
    public void retrySubscribe() {
        OpcUaClient client = null;
        try {
            log.info("重试订阅");
            //等待释放资源???
            try {
                long WAIT_TIME = frequencyProperties.getPlcRetryTime();
//                Strand.sleep(WAIT_TIME);
                Thread.sleep(WAIT_TIME);
            } catch (InterruptedException e) {
                log.info(e.getMessage());
                e.printStackTrace();
            }
            //确保在读写之前 创建好这个连接
            client = opcUaService.createClient();
            if(client == null){
                log.info("失败数量达到极限");
                Map map = new HashMap<>();
                map.put("message", "··已达到最大重连次数1，请重启软件··");
                String json = JSON.toJSONString(map);
                webSocketServer.sendToAllClient(json);
                jSerialCommIOService.buzzerControl();
                return;
            }

            client.connect().get();
            String[] nodeIds = opcUaService.browseNode(client, null);
            log.info("重试订阅检测到的可用节点: " + Arrays.toString(nodeIds));

            // 使用列表手动将 NodeId 逐个添加到新节点数组
            // 这里的 list 用于临时保存动态添加的 NodeId 对象
            List<String> nodeIdList = new ArrayList<>();
            String nodeString = Arrays.toString(nodeIds);
            String carNum = carNodeProperties.getCarNum();
            String carType = carNodeProperties.getCarType();
            String repeat = carNodeProperties.getRepeat();
            boolean containsNull1 = nodeString.contains(carNum);
            boolean containsNull2 = nodeString.contains(carType);
            boolean containsNull3 = nodeString.contains(repeat);
//            log.info("nodeIds1是"+ Arrays.toString(nodeIds));
            if (nodeIds != null && containsNull1 && containsNull2 && containsNull3) {
                log.info("nodeIds2是"+ Arrays.toString(nodeIds));
//                for (String nodeId : nodeIds) {
//                    // 打印每个 NodeId
////                log.info("处理 NodeId: " + nodeId);
//                    // 将每个 NodeId 添加到 List 中
//                    nodeIdList.add(nodeId); // 添加到列表
//                }
                nodeIdList.addAll(Arrays.asList(nodeIds));

//                Map map = new HashMap<>();
//                map.put("message", "...创建OPC客户端成功...");
//                String json = JSON.toJSONString(map);
//                webSocketServer.sendToAllClient(json);
            } else {
                log.info("nodeIds为空，或者检测不到相关节点，释放资源。。。");
                try {
                    client.disconnect().get();
//                        jSerialCommIOService.yellowUp();
                    Map<String, String> map0 = new HashMap<>();
                    map0.put("car1Num", "PLC重连中");
                    map0.put("car1Type", "PLC重连中");
                    map0.put("repeat1", "PLC重连中");
                    map0.put("standard1min", "");
                    map0.put("standard1max", "");
                    CacheUtil.removeFromCache("standard1");
                    //CacheUtil.removeFromCache("standard1max");
                    map0.put("car2Num", "PLC重连中");
                    map0.put("car2Type", "PLC重连中");
                    map0.put("repeat2", "PLC重连中");
                    map0.put("standard2min", "");
                    map0.put("standard2max", "");
                    CacheUtil.removeFromCache("standard2");
                    //CacheUtil.removeFromCache("standard2max");
                    //把map转为json
                    String json0 = JSON.toJSONString(map0);
                    log.info("plc已断开的json是"+json0);
                    webSocketServer.sendToAllClient(json0);//推消息

                } catch (Exception e0) {
                    log.info("关闭客户端时发生异常: " + e0.getMessage());
                }
                retrySubscribe();
            }
            opcUaService.subscribe(client, nodeIdList);
        } catch (Exception e) {
            log.info("catch抛出异常");
            if (client != null) {
                log.info("catch释放资源");
                try {
                    client.disconnect().get();
                } catch (Exception e1) {
                    log.info("关闭客户端时发生异常: " + e1.getMessage());
                }
            }
            log.info(e.getMessage());
            e.printStackTrace();
//            retrySubscribe();//不能在throw中循环调用retrySubscribe()
//            throw new RuntimeException(e);
        } finally {
// 确保在方法结束时释放资源
            if (client != null) {
                log.info("finally释放资源");
                try {
                    client.disconnect().get();
                } catch (Exception e2) {
                    log.info("关闭客户端时发生异常: " + e2.getMessage());
                }
            }
        }
    }

    @Override
    public int subscribe(OpcUaClient client, List<String> nodeIds) throws Exception {
//        SimpleCache cache = new SimpleCache();
        AtomicInteger atomicId = new AtomicInteger();
        //设个一次性缓存，用于实现刚打开页面时，先运行四次
        CacheUtil.putInCache("4times", ipProperties.getTimes());//4

        Map<NodeId, Object> monitoredValues = new HashMap<>();

        client
                .getSubscriptionManager()
                //订阅频率//MessageConstant.monitorNodeFrequency
                .createSubscription(frequencyProperties.getMonitorNodeFrequency())
                .thenAccept(subscription -> {
                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();

                    for (String nodeId : nodeIds) {
//                        log.info("nodeId是"+nodeId);
                        // 解析 NodeId
                        String[] parts = nodeId.replace("NodeId{", "").replace("}", "").split(", ");
                        String namespace = parts[0].split("=")[1]; // 获取 ns= 的值
                        String id = parts[1].split("=")[1]; // 获取 id= 的值

                        // 构建目标格式的字符串，注意使用 s= 来表示字符串 ID
                        String formattedNodeId = "ns=" + namespace + ";s=" + id; // 使用 s= 表示字符串类型的 NodeId

                        // 将目标格式字符串转换为 NodeId 对象
                        NodeId nodeId0 = NodeId.parse(formattedNodeId); // 解析字符串为 NodeId
//                        log.info("格式化节点后"+nodeId0);
                        // 创建 ReadValueId
                        ReadValueId readValueId = new ReadValueId(nodeId0, AttributeId.Value.uid(),
                                null, null);

                        // 创建监控的参数
                        MonitoringParameters parameters = new MonitoringParameters(
                                UInteger.valueOf(atomicId.getAndIncrement()), // 生成唯一的监控参数 ID
                                (double) frequencyProperties.getMonitorNodeFrequency(), //MessageConstant.monitorNodeFrequency                                      // 更新间隔
                                null,                                         // 最大通知时间
                                UInteger.valueOf(15),                         // 最大通知数量
                                true                                           // 使用数据变化的通知
                        );

                        // 创建监控项请求
                        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                        requests.add(request);  // 将请求添加到列表中
                    }

                    // 创建监控项，并且注册变量值改变时的回调函数
                    subscription.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                // 获取节点 ID 和新值
                                NodeId monitoredNodeId = it.getReadValueId().getNodeId();
                                Object newValue = val.getValue().getValue();

                                // 将新值存储到 Map 中
                                monitoredValues.put(monitoredNodeId, newValue);

                                // 打印输出监控到的值
//                                log.info("节点: " + monitoredNodeId);
//                                log.info("值: " + newValue);
                            })
                    );

                    //报警次数统计
                    Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
//            log.info("alarmsTime是"+alarmsTime);
                    if(alarmsTime == null){
                        log.info("新建报警统计缓存");
                        LambdaQueryWrapper<CarStatus> queryWrapper = new LambdaQueryWrapper<>();
                        //匹配扭力不是正常的以及是待处理的告警
                        queryWrapper.ne(CarStatus::getAlarmLevel, CarStatus.AlarmLevel.normal)
                                .eq(CarStatus::getCheckStatus, CarStatus.CheckStatus.waitForCheck);
                        //只匹配今天的
                        LocalDate today = LocalDate.now();
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                        String todayStr = today.format(formatter);
                        queryWrapper.like(CarStatus::getCreateTime, todayStr);
                        int count = carStatusMapper.selectCount(queryWrapper);
                        CacheUtil.putInCache("alarmsTime",count);
                        log.info("今天的报警统计缓存是{}", count);
                    }else {
                        log.info("报警统计缓存已存在");
                        //后面加上了空螺丝缓存，就不能这样写了？？
//                        LambdaQueryWrapper<CarStatus> queryWrapper = new LambdaQueryWrapper<>();
//                        //匹配扭力不是正常的以及是待处理的告警
//                        queryWrapper.ne(CarStatus::getAlarmLevel, CarStatus.AlarmLevel.normal)
//                                .eq(CarStatus::getCheckStatus, CarStatus.CheckStatus.waitForCheck);
//                        //只匹配今天的
//                        LocalDate today = LocalDate.now();
//                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//                        String todayStr = today.format(formatter);
//                        queryWrapper.like(CarStatus::getCreateTime, todayStr);
//                        int count = carStatusMapper.selectCount(queryWrapper);
//                        //不一致，则更新缓存
//                        if(count != (int) alarmsTime){
//                            log.info("----更新报警统计缓存----");
//                            CacheUtil.putInCache("alarmsTime",count);
//                            log.info("今天的报警统计缓存是{}", count);
//                            Map map0 = new HashMap();
//                            map0.put("alarmsTime",count);
//                            String json = JSON.toJSONString(map0);
//                            webSocketServer.sendToAllClient(json);
//                        }

                    }

                    // 每秒将监控到的数据缓存起来
                    Timer timer = new Timer();
                    timer.scheduleAtFixedRate(new TimerTask() {
                         //用于储存监控的值，用于与下一次监控到的值进行比较
                        // 设定最大重试次数
                        final int maxRetries = frequencyProperties.getPlcRetryFrequency();
//                        final int maxRetries0 = 5;
                        int attempts = 0;//plc一开始就断开的尝试重连机会
                        //弹窗次数
                        int alertTime = 1;
                        //
//                        int cacheTime = 1;
//                        int attempts0 = 0;//plc工作中突然断开的尝试重连机会
                        @Override
                        public void run() {
                            // 返回监控值的逻辑
                            Map<String, String> i = null;
//                            try {
                                //TODO 测试
                                //检查有没有红灯缓存，如果没有就新建一个
//                                Object object = CacheUtil.getFromCache("redLight");
//                                if (object == null){
//                                    log.info("新建--");
//                                    List<Long> redLight = new ArrayList<>();
//                                    redLight.add(Long.valueOf("121"));
//                                    CacheUtil.putInCache("redLight",redLight);
//                                }else {//如果有就加多一个
//                                    log.info("已有--");
//                                    //Object object = CacheUtil.getFromCache("redLight");
//                                    List<Long> redLight = (List<Long>) object;//TODO 拧紧枪测试。。。
//                                    redLight.add(Long.valueOf("212"));
//                                    CacheUtil.putInCache("redLight",redLight);
//                                }

                                i = sendToFrontEnd(monitoredValues);
//                                log.info("i是什么"+i);
//                            }
//                            catch (Exception e) {
////                                retrySubscribe();
//
////                                Map map = new HashMap();
////                                map.put("message", "··已达到最大重连次数，请重启软件··");
////                                String json = JSON.toJSONString(map);
////                                webSocketServer.sendToAllClient(json);
//                                log.info("重连????");
//                                e.printStackTrace();// 打印错误信息，但不会中断程序
////                                throw new RuntimeException(e);
//                            }
                            if (i == null) {//plc断开
                                attempts = attempts + 1;
                                // 没有监控到数据，取消当前任务并立即跳到下一个监控
                                log.info("监控数据为空，立即跳到下一个周期，plc初次连接，给了{}次机会",attempts);

                                if(attempts >= maxRetries){//>=
//                                    try {
//                                    jSerialCommIOService.greenOut();
//                                        //蜂鸣器响5秒
//                                        jSerialCommIOService.buzzerControl();
                                        jSerialCommIOService.redUp();
                                        log.info("重连?------------------?");
//                                        Map map = new HashMap();
//                                        map.put("message", "··PLC连接失败，重连中··");
//                                        String json = JSON.toJSONString(map);
//                                        webSocketServer.sendToAllClient(json);

                                        retrySubscribe();
//                                    } catch (Exception e) {
//                                        log.info("重连???");
//                                        retrySubscribe();
//                                        throw new RuntimeException(e);
//                                    }
                                }
                                return;
                            }else {
                                if (alertTime == 1){
                                    //红灯灭
//                                    jSerialCommIOService.redOut();
                                    //绿灯亮
                                    jSerialCommIOService.greenUp();
                                    Map map = new HashMap();
                                    map.put("message", "····PLC连接成功····");
                                    String json = JSON.toJSONString(map);
                                    webSocketServer.sendToAllClient(json);
                                    alertTime = alertTime -1;
                                }
                            }


                            String car1NumCache = (String) CacheUtil.getFromCache("carNum1");
                            car1NumCache = (car1NumCache != null && !car1NumCache.isEmpty()) ? car1NumCache : "";
                            String car1TypeCache = (String) CacheUtil.getFromCache("carType1");
                            car1TypeCache = (car1TypeCache != null && !car1TypeCache.isEmpty()) ? car1TypeCache : "";
                            String repeat1Cache = (String) CacheUtil.getFromCache("repeat1");
                            repeat1Cache = (repeat1Cache != null && !repeat1Cache.isEmpty()) ? repeat1Cache : "";
                            String car2NumCache = (String) CacheUtil.getFromCache("carNum2");
                            car2NumCache = (car2NumCache != null && !car2NumCache.isEmpty()) ? car2NumCache : "";
                            String car2TypeCache = (String) CacheUtil.getFromCache("carType2");
                            car2TypeCache = (car2TypeCache != null && !car2TypeCache.isEmpty()) ? car2TypeCache : "";
                            String repeat2Cache = (String) CacheUtil.getFromCache("repeat2");
                            repeat2Cache = (repeat2Cache != null && !repeat2Cache.isEmpty()) ? repeat2Cache : "";


                            String car1Type = (i.get("car1Type") != null && !i.get("car1Type").isEmpty()) ?
                                    i.get("car1Type").trim() : "";
                            String repeat1 = (i.get("repeat1") != null && !i.get("repeat1").isEmpty()) ?
                                    i.get("repeat1").trim() : "";
                            String car1Num = (i.get("car1Num") != null && !i.get("car1Num").isEmpty()) ?
                                    i.get("car1Num").trim() : "";
                            log.info("当前车1是"+car1Num.trim()+"-"+car1Type.trim()+"-"+repeat1.trim());

                            String car2Type = (i.get("car2Type") != null && !i.get("car2Type").isEmpty()) ?
                                    i.get("car2Type").trim() : "";
                            String repeat2 = (i.get("repeat2") != null && !i.get("repeat2").isEmpty()) ?
                                    i.get("repeat2").trim() : "";
                            String car2Num = (i.get("car2Num") != null && !i.get("car2Num").isEmpty()) ?
                                    i.get("car2Num").trim() : "";
                            log.info("当前车2是"+car2Num.trim()+"-"+car2Type.trim()+"-"+repeat2.trim());


                            if((car1NumCache.isEmpty() &&
                                    car1TypeCache.isEmpty() &&
                                    repeat1Cache.isEmpty())
//                                    ||
                            && //都是空的时候才重连
                               (car2NumCache.isEmpty() &&
                                       car2TypeCache.isEmpty() &&
                                       repeat2Cache.isEmpty())) {
                                retryAndNoData(car1Num, car1Type, repeat1,
                                        car2Num, car2Type, repeat2);
                            }


//                            System.out.println(car1NumCache+"|car1Num|"+car1Num);
//                            System.out.println(car1TypeCache+"|car1Type|"+car1Type);
//                            System.out.println(repeat1Cache+"|repeat1|"+repeat1);
                            if (car1NumCache.equals(car1Num) &&
                                    car1TypeCache.equals(car1Type) &&
                                    repeat1Cache.equals(repeat1)) {
                                // 与上一次监控到的值相同，取消当前任务并立即跳到下一个周期
                                log.info("与上一次监控到的car1值相同，等待跳到下一个周期.");
                            }else {
                                //查数据库，上一辆车的1-16的类型的螺丝是否够数，车辆ID缓存
                                Object lastCar = CacheUtil.getFromCache("lastCar1");
                                if (lastCar != null) {
                                    Car car = (Car) lastCar;
                                    if (car.getId() != null) {
                                        LambdaQueryWrapper<Screw> queryWrapper = new LambdaQueryWrapper<>();
                                        queryWrapper.eq(Screw::getCarId, car.getId());
                                        //从工位1存进去的螺丝他的类型一定是1-16的
                                        queryWrapper.eq(Screw::getWorkingPositionId, MessageConstant.workingPosition1);
                                        int count = screwMapper.selectCount(queryWrapper);
                                        log.info(car.getId()+"工位一的count是："+count);
                                        //不能是20，因为工位二和工位一不是同一辆车的，必须分开，否则工位一的车未流到工位二之前会一直报警
                                        if (count < 16 && count > 0) {
                                            //螺丝数量不够，报警
                                            log.info("上一辆车"+lastCar+"没拧够16颗"+count);
                                            //报警次数统计
                                            Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
                                            if(alarmsTime != null){
                                                int alarmsTimeCount = (Integer) alarmsTime + (16 - count);
                                                CacheUtil.putInCache("alarmsTime", alarmsTimeCount);
                                                log.info("空螺丝+普通警报统计缓存是{}", alarmsTimeCount);
                                                Map map0 = new HashMap();
                                                map0.put("alarmsTime",alarmsTimeCount);
                                                String json = JSON.toJSONString(map0);
                                                webSocketServer.sendToAllClient(json);
                                            }
//                                            System.out.println("上一辆车"+lastCar+"没拧够16颗"+count);
                                            jSerialCommIOService.buzzerControl();
                                            //给这辆车标上缺少螺丝，流到工位二才知道是否有缺失，再设置
//                                            car.setScrewIsNull("Null");
//                                            carService.updateById(car);
                                        }
                                    }
                                }

//                                //验证上一辆车两边是否都拧够8棵螺丝了
//                                Object x = CacheUtil.getFromCache("screwNum51");
//                                Object y = CacheUtil.getFromCache("screwNum52");
//                                if (x != null && y != null) {//能够排除掉第一次打开软件时上一次缓存还没有的时候
//                                    int screwNum51 = (int) x;
//                                    int screwNum52 = (int) y;
//                                    log.info("screwNum51是：{},54是{}",screwNum51,screwNum52);
//                                    if(screwNum51 > 0 && screwNum52 > 0) {//排除掉完全没有拧的工位
//                                        if (screwNum51 < 8 || screwNum52 < 8) {
//                                            System.out.println("上一辆车没拧够16颗");
//                                            jSerialCommIOService.buzzerControl();
//                                            Object lastCar = CacheUtil.getFromCache("lastCar");
//                                            if(lastCar != null){
//                                                Car car = (Car) lastCar;
//                                                car.setScrewIsNull("Null");
//                                                carService.updateById(car);
//                                                //更新缓存updateById
//                                                CacheUtil.putInCache("lastCar",car);
//                                            }
//
//                                        }
//                                    }
//
//                                }

                                //防止plc断开的时候也清理前端的告警点
                                //清理工位一的扭力标准缓存
                                //！！！！！！！！！！！
//                                CacheUtil.removeFromCache("standard1");
                                //应该要更新工位一的扭力标准缓存
                                //就不应该动？？？？？

                                //CacheUtil.removeFromCache("standard1max");
//                                CacheUtil.removeFromCache("standard2");
                                //else if(!car1Num.isEmpty() && !car1Type.isEmpty() && !repeat1.isEmpty())
                                // 与上一次监控到的值不同，继续监控下一次
                                log.info("与上一次监控到的car1值不同，缓存以及保存当前车的信息，让心跳端读取");
                                //更新缓存
                                CacheUtil.putInCache("carNum1", car1Num.trim());
                                CacheUtil.putInCache("carType1", car1Type.trim());
                                CacheUtil.putInCache("repeat1", repeat1.trim());
                                //无论之前是否是红灯，清理红灯缓存并统统绿灯
//                                List<Long> redLight = new ArrayList<>();
//                                CacheUtil.putInCache("redLight", redLight);
////                                CacheUtil.removeFromCache("redLight");
//                                jSerialCommIOService.greenUp();
                                //清理前端的螺丝缓存
                                for (int count = 1; count <= 16; count++) {
                                    CacheUtil.removeFromCache("screw"+ count);
//                                    CacheUtil.putInCache("screw"+ count, null);
//                                    CacheUtil.putInCache("screw"+ count, 0.00); // 也可以用 null
                                }
                                LambdaQueryWrapper<Car> carWrapper = new LambdaQueryWrapper<>();

//                                错误了：需求是 “先获取数据库中最新的那条记录，再检查它是否符合 car1Type 和 repeat1 的条件”，
//                                 但当前代码的逻辑是 “先筛选出符合 car1Type、repeat1、workingPosition1 条件的记录，
//                                 再从中取最新的一条”，这两种逻辑是不同的。

//                                carWrapper//.like(Car::getCarId, repeat1.trim())
//                                        .eq(Car::getCarType, car1Type.trim())
//                                        .eq(Car::getRepeatNum, repeat1.trim())
//                                        //只查工位一的车数据，工位二的车数据就别参进来了
//                                        .eq(Car::getWorkingPositionId, MessageConstant.workingPosition1)
//                                        // 按时间字段降序排序（最新的排在前面）
//                                        .orderByDesc(Car::getCreateTime)  // 替换为实际的时间字段，如updateTime
//                                        // 限制只查询1条（取最新的那条）
//                                        .last("LIMIT 1");  // MySQL数据库用LIMIT 1，Oracle用ROWNUM <= 1

                                // 1. 构建查询条件：只限制工位，不限制carType和repeatNum，取最新的一条记录
                                LambdaQueryWrapper<Car> queryWrapper = new LambdaQueryWrapper<>();
                                queryWrapper.eq(Car::getWorkingPositionId, MessageConstant.workingPosition1) // 只限制工位
                                        .orderByDesc(Car::getCreateTime) // 按时间降序（最新的在前）
                                        .last("LIMIT 1"); // 取最新的一条
// 2. 查询数据库中最新的那条记录（符合工位条件）
                                Car latestCar = carMapper.selectOne(queryWrapper);
// 3. 检查这条最新记录是否符合 car1Type 和 repeat1 的条件
                                boolean isMatch = false;
                                if (latestCar != null) {
                                    //  trim() 处理，避免空格影响判断
                                    boolean typeMatch = car1Type.trim().equals(latestCar.getCarType());
                                    boolean repeatMatch = repeat1.trim().equals(latestCar.getRepeatNum());
                                    isMatch = typeMatch && repeatMatch;
                                }
// 4. 根据结果处理业务
//                                if (isMatch) {
//                                    System.out.println("最新记录符合条件");
//                                    //最新那条就是现在读到的
//                                } else {
//                                    System.out.println("最新记录不符合条件（或无记录）");
//                                    //最新那条不是现在读到的，需要插入
//                                }

//                                Integer count = carMapper.selectCount(carWrapper);
//                                (count != null && count == 0)

                                List<Car> latest1Cars = carMapper.selectList(carWrapper);
                                System.out.println("<latest1Cars是>"+latest1Cars);

//                                carWrapper.eq(Car::getCarId, car1Num.trim());
//                                carWrapper.eq(Car::getCarType, car1Type.trim());
//                                carWrapper.eq(Car::getRepeatNum, repeat1.trim());
                                if(!isMatch &&//latest1Cars.isEmpty()
                                        (!car1Num.trim().isEmpty() &&
                                        !car1Type.trim().isEmpty() &&
                                        !repeat1.trim().isEmpty() ) ) {
                                    // 如果数据库中没有该条数据，则插入该条数据
                                    log.info("数据库中没有" + car1Num + "这辆车");
                                    System.out.println("数据库中没有" + car1Num + "这辆车");
                                    Car car = new Car();
                                    car.setCarId(car1Num.trim());
                                    car.setCarType(car1Type.trim());
                                    car.setRepeatNum(repeat1.trim());
                                    //车身拼接过前缀之后才能存进数据库
                                    Object carNumPrefix = CacheUtil.getFromCache("carNumPrefix");
                                    String carNumPrefixString = "";
                                    if (carNumPrefix != null) {
                                        carNumPrefixString = String.valueOf(carNumPrefix);
                                    }

                                    //车身拼接过前缀之后才能存进数据库
                                    Object timePrefix = CacheUtil.getFromCache("timePrefix");
                                    String timePrefixString = "";
                                    if (timePrefix != null) {
                                        timePrefixString = String.valueOf(timePrefix);
                                    }

                                    System.out.println("保存车辆1前："+timePrefixString);

                                    if (car1Num.trim().length() >= 2 && !car1Type.trim().equals("未知车型") && !car1Num.trim().contains("null")) {
                                        if ((car1Num.trim().contains(carNumPrefixString) ||
                                                car1Num.trim().contains(timePrefixString)) &&
                                                //确报拼接过连番号
                                                car1Num.trim()
                                                        .substring(car1Num.trim().length() - 2)
                                                        .contains(repeat1.trim())) {
                                            log.info(car1Num.trim() + "保存车辆1" + car);
                                            car.setWorkingPositionId(MessageConstant.workingPosition1);
                                            carService.save(car);
                                            log.info("保存车辆1成功后，立即获取主键："+car.getId());
                                            //在这里更新不太好？？？，如果是第一次打开软件。。。没事。。。
                                            CacheUtil.putInCache("lastCar1",car);
                                        }
                                    }

                                }

                            }


                            //弃用
//                            if(!repeat1Cache.equals(repeat1) ||
//                                    !repeat2Cache.equals(repeat2)){
//                                //新车来了，无论之前是否是红灯，清理红灯缓存并统统绿灯
//                                List<Long> redLight = new ArrayList<>();
//                                CacheUtil.putInCache("redLight", redLight);
////                                log.info("绿灯亮?");
//                                jSerialCommIOService.greenUp();
//                            }


//                            System.out.println(car2NumCache+"|car2Num|"+car2Num);
//                            System.out.println(car2TypeCache+"|car2Type|"+car2Type);
//                            System.out.println(repeat2Cache+"|repeat2|"+repeat2);

                            if (car2NumCache.equals(car2Num) &&
                                    car2TypeCache.equals(car2Type) &&
                                    repeat2Cache.equals(repeat2)) {
                                // 与上一次监控到的值相同，取消当前任务并立即跳到下一个周期
                                log.info("与上一次监控到的car2值相同，等待跳到下一个周期.");
                            }else {
                                //查数据库，上一辆车的17-20的类型的螺丝是否够数，车辆ID缓存
                                Object lastCar = CacheUtil.getFromCache("lastCar2");
                                if (lastCar != null) {
                                    Car car = (Car) lastCar;
                                    if (car.getId() != null) {
                                        LambdaQueryWrapper<Screw> queryWrapper = new LambdaQueryWrapper<>();
                                        queryWrapper.eq(Screw::getCarId, car.getId());
                                        //从工位2存进去的螺丝他的类型一定是17-20的
                                        queryWrapper.eq(Screw::getWorkingPositionId, MessageConstant.workingPosition2);
                                        int count = screwMapper.selectCount(queryWrapper);
                                        log.info(car.getId()+"工位二count是："+count);
                                        //不能是20，因为工位二和工位一不是同一辆车的，必须分开，否则工位一的车未流到工位二之前会一直报警
                                        if (count < 4 && count > 0) {
                                            //螺丝数量不够，报警
                                            log.info("上一辆车"+lastCar+"没拧够4颗"+count);
//                                            System.out.println("上一辆车"+lastCar+"没拧够4颗"+count);
                                            //报警次数统计
                                            Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
                                            if(alarmsTime != null){
                                                int alarmsTimeCount = (Integer) alarmsTime + (4 - count);
                                                CacheUtil.putInCache("alarmsTime", alarmsTimeCount);
                                                log.info("空螺丝+普通警报统计缓存是{}", alarmsTimeCount);
                                                Map map0 = new HashMap();
                                                map0.put("alarmsTime",alarmsTimeCount);
                                                String json = JSON.toJSONString(map0);
                                                webSocketServer.sendToAllClient(json);
                                            }

                                            jSerialCommIOService.buzzerControl();
                                            //给这辆车标上缺少螺丝
                                            car.setScrewIsNull("Null");
                                            carService.updateById(car);
                                        }
                                    }
                                }



//                                //验证上一辆车两边是否都拧够2棵螺丝了
//                                Object x = CacheUtil.getFromCache("screwNum53");
//                                Object y = CacheUtil.getFromCache("screwNum54");
//                                if (x != null && y != null) {//能够排除掉第一次打开软件时上一次缓存还没有的时候
//                                    int screwNum53 = (int) x;
//                                    int screwNum54 = (int) y;
//                                    log.info("screwNum53是{}：54是{}",screwNum53,screwNum54);
//                                    if(screwNum53 > 0 && screwNum54 > 0){//排除掉完全没有拧的工位
//                                        if (screwNum53 < 2 || screwNum54 < 2) {
//                                            System.out.println("上一辆车没拧够4颗");
//                                            jSerialCommIOService.buzzerControl();
//                                        }
//                                    }
//                                }

                                //防止plc断开的时候的情况也清理前端的告警点
                                //else if(!car2Num.isEmpty() && !car2Type.isEmpty() && !repeat2.isEmpty())
                                // 与上一次监控到的值不同，继续监控下一次
                                log.info("与上一次监控到的car2值不同，缓存以及保存当前车的信息，让心跳端读取");
                                //清理工位二的扭力标准缓存
//                                CacheUtil.removeFromCache("standard1");
                                //CacheUtil.removeFromCache("standard1max");
                                //不应该动？？？？
//                                CacheUtil.removeFromCache("standard2");

                                //CacheUtil.removeFromCache("standard2max");
                                //更新缓存
                                CacheUtil.putInCache("carNum2", car2Num.trim());
                                CacheUtil.putInCache("carType2", car2Type.trim());
                                CacheUtil.putInCache("repeat2", repeat2.trim());

                                //无论之前是否是红灯，清理红灯缓存并统统绿灯
//                                List<Long> redLight = new ArrayList<>();
//                                CacheUtil.putInCache("redLight", redLight);
////                                CacheUtil.removeFromCache("redLight");
//                                jSerialCommIOService.greenUp();
                                //清理前端的螺丝缓存
                                for (int count = 17; count <= 20; count++) {
                                    CacheUtil.removeFromCache("screw"+ count);
//                                    CacheUtil.putInCache("screw"+ count, null);
//                                    CacheUtil.putInCache("screw"+ count, 0.00); // 也可以用 null
                                }

                                log.info("当前车2是"+car2Num.trim()+"-"+car2Type.trim()+"-"+repeat2.trim());


                                //TODO 工位二就不用存了，因为工位一存的车辆，一定会流到工位二，而且工位二直接读取工位一的连番-3就行了
                                //TODO 工位二只保存刚打开软件的前四次数据
                                Object fourTimes = CacheUtil.getFromCache("4times");
                                int fourTimesInt = 0;
                                if(fourTimes != null){
                                    fourTimesInt = Integer.parseInt(fourTimes.toString().trim());
                                }
                                log.info("fourTimesInt是："+fourTimesInt);
//                                System.out.println("fourTimesInt是："+fourTimesInt);

                                //前3条读盘并存入数据库
                                if(fourTimesInt > 0) {
                                    log.info("fourTimesInt减到了："+fourTimesInt);
                                    System.out.println("fourTimesInt减到了："+fourTimesInt);

//                                    LambdaQueryWrapper<Car> carWrapper = new LambdaQueryWrapper<>();
//                                    carWrapper.eq(Car::getCarId, car2Num.trim())
//                                            .eq(Car::getCarType, car2Type.trim())
//                                            .eq(Car::getRepeatNum, repeat2.trim())
//                                            //只查工位一的车数据，工位二的车数据就别参进来了
////                                            .eq(Car::getWorkingPositionId, MessageConstant.workingPosition1)
//                                            // 按时间字段降序排序（最新的排在前面）
//                                            .orderByDesc(Car::getCreateTime)  // 替换为实际的时间字段，如updateTime
//                                            // 限制只查询倒数第4条
//                                            .last("LIMIT 8"); // 取最新4条  // MySQL数据库用LIMIT 3, 1 LIMIT 1，Oracle用ROWNUM <= 1
//LIMIT 3, 1 是用于查询具体记录（如 selectList）时限制返回行数的，不应该用在 selectCount 中

                                    // 1. 先查询全表最新的8条记录（不附加筛选条件，只按时间排序）
                                    LambdaQueryWrapper<Car> latest8Wrapper = new LambdaQueryWrapper<>();
                                    latest8Wrapper.orderByDesc(Car::getCreateTime) // 按时间降序（最新的在前）
                                            .last("LIMIT 6"); // 取最新的8条（MySQL语法）

                                    List<Car> latest8Cars = carMapper.selectList(latest8Wrapper);

// 2. 从这8条记录中，筛选出符合条件的（carId、carType、repeatNum匹配）
                                    List<Car> matchedCars = new ArrayList<>();
                                    if (latest8Cars != null && !latest8Cars.isEmpty()) {
                                        for (Car car : latest8Cars) {
                                            // 处理空指针：先判断字段非空，再trim比较
                                            boolean idMatch = car.getCarId() != null && car.getCarId().equals(car2Num.trim());

                                            boolean typeMatch = car.getCarType() != null && car.getCarType().equals(car2Type.trim());

                                            boolean repeatMatch = car.getRepeatNum() != null && car.getRepeatNum().equals(repeat2.trim());

                                            // 三个条件都满足时，加入结果集
                                            if (idMatch && typeMatch && repeatMatch) {
                                                matchedCars.add(car);
                                                //如果找到了一条，就没必要再循环了，跳出循环节约性能
                                                break;
                                                //                                                // 给外层循环定义标签 outerLoop
//                                                outerLoop:
//                                                for (int i = 0; i < 3; i++) {
//                                                    System.out.println("外层循环，i = " + i);
//                                                    for (int j = 0; j < 3; j++) {
//                                                        if (i == 1 && j == 1) {
//                                                            break outerLoop; // 跳出标签为 outerLoop 的外层循环
//                                                        }
//                                                        System.out.println("  内层循环，j = " + j);
//                                                    }
//                                                }
                                            }
                                        }
                                    }

// 3. 后续使用筛选后的结果（matchedCars即为“全表最新8条中符合条件的记录”）
//                                    System.out.println("符合条件的记录数：" + matchedCars.size());

//                                    Integer count = carMapper.selectCount(carWrapper);
//                                    System.out.println("<count是>"+count);
//                                    (count != null && count == 0)

//                                    List<Car> latest4Cars = carMapper.selectList(carWrapper);
//                                    System.out.println("<matchedCars是>"+matchedCars);

//                                carWrapper.eq(Car::getCarId, car2Num.trim());
//                                carWrapper.eq(Car::getCarType, car2Type.trim());
//                                carWrapper.eq(Car::getRepeatNum, repeat2.trim());
                                    if (matchedCars.isEmpty() &&//完全找不到之前存过这条数据的记录时，才能插入
                                            (!car2Num.trim().isEmpty() &&
                                                    !car2Type.trim().isEmpty() &&
                                                    !repeat2.trim().isEmpty())) {
                                        // 如果数据库中没有该条数据，则插入该条数据
                                        log.info("数据库中没有" + car2Num + "这辆车");
                                        Car car = new Car();
                                        car.setCarId(car2Num.trim());
                                        car.setCarType(car2Type.trim());
                                        car.setRepeatNum(repeat2.trim());
                                        //车身拼接过前缀之后才能存进数据库，拿到车身号前缀
                                        Object carNumPrefix = CacheUtil.getFromCache("carNumPrefix2");
                                        String carNumPrefixString = "";
                                        if (carNumPrefix != null) {
                                            carNumPrefixString = String.valueOf(carNumPrefix);
                                        }

                                        if (car2Num.trim().length() >= 2
                                                && !car2Type.trim().equals("未知车型")
                                                && !car2Num.trim().contains("null")) {
                                            if (car2Num.trim().contains(carNumPrefixString) &&
                                                    //确报拼接过连番号
                                                    car2Num.trim()
                                                            .substring(car2Num.trim().length() - 2)
                                                            .contains(repeat2.trim())) {
                                                log.info(car2Num.trim() + "((只保存刚开始的四次)不用保存了，工位一就已经存过了)保存车辆2" + car);
                                                car.setWorkingPositionId(MessageConstant.workingPosition2);
                                                carService.save(car);
                                                log.info("保存车辆2成功后，立即获取主键："+car.getId());
                                                //在这里更新不太好？？？，如果是第一次打开软件。。。跳3格之后工位二就进不来了
                                                //都写，"4times"大于0时，在这里更新，
                                                //     "4times"等于0时，
                                                //     在carMapper.selectOne更新
                                                CacheUtil.putInCache("lastCar2",car);
                                            }
                                        }

                                    }
                                //3条之后读的数据库，不用存
                                }else {
                                    log.info("数据库中已存在" + car2Num + "这辆车");
                                    //更新工位二的上一辆车缓存信息，用于查询刚刚溜过去的车的螺丝是否拧齐了
                                    Object targetCar = CacheUtil.getFromCache("targetCar");
                                    if (targetCar != null){
                                        CacheUtil.putInCache("lastCar2",targetCar);
                                    }

                                }

                            }
                        }
                    }, 0, frequencyProperties.getCacheFrequency()); // 每 1000 ms 运行一次MessageConstant.cacheFrequency
                }).get();
        // 持续订阅
        //让线程“永久等待”而不退出
        Thread.sleep(Long.MAX_VALUE);
        return 0;
    }


    //@Suspendable
    private void retryAndNoData(String car1Num, String car1Type, String repeat1,
                                String car2Num, String car2Type, String repeat2) {
        if(car1Num.isEmpty() &&
                car1Type.isEmpty() &&
                repeat1.isEmpty() &&
                car2Num.isEmpty() &&
                car2Type.isEmpty() &&
                repeat2.isEmpty()){
//            log.info("PLC断开重连");
//            log.info("无数据");
            Map<String, String> map0 = new HashMap<>();
            map0.put("car1Num", "无数据");
            map0.put("car1Type", "无数据");
            map0.put("repeat1", "无数据");
            map0.put("standard1min",  "");
            map0.put("standard1max",  "");
            map0.put("car2Num", "无数据");
            map0.put("car2Type", "无数据");
            map0.put("repeat2", "无数据");
            map0.put("standard2min",  "");
            map0.put("standard2max",  "");
            //把map转为json
            String json0 = JSON.toJSONString(map0);
            log.info("plc无数据的json是"+json0);
            webSocketServer.sendToAllClient(json0);//推消息
            CacheUtil.removeFromCache("standard1");
            //CacheUtil.removeFromCache("standard1max");
            CacheUtil.removeFromCache("standard2");
            //CacheUtil.removeFromCache("standard2max");
//             try {
//                 waitTime = Math.min(frequencyProperties.getMonitorNodeFrequency()
//                         + 500, MAX_WAIT_TIME);
//                 Thread.sleep(waitTime);
//                } catch (Exception e) {
//                throw new RuntimeException(e);
//            }

            try {
                Thread.sleep(frequencyProperties.getMonitorNodeFrequency());
            } catch (Exception e) {
                log.info(e.getMessage());
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
//            Map map = new HashMap();
//            map.put("message", "····PLC已无数据，请检查设备···");
//            String json = JSON.toJSONString(map);
//            webSocketServer.sendToAllClient(json);//推消息
//            retrySubscribe();
        }else if(car1Num.isEmpty() &&
                car1Type.isEmpty() &&
                repeat1.isEmpty() &&
                !car2Num.isEmpty() &&
                !car2Type.isEmpty() &&
                !repeat2.isEmpty()){
            log.info("只是工位一没有数据，PLC不用重连");
            Map<String, String> map0 = new HashMap<>();
            map0.put("car1Num", "无数据");
            map0.put("car1Type",  "无数据");
            map0.put("repeat1",  "无数据");
            map0.put("standard1min",  "");
            map0.put("standard1max",  "");
            CacheUtil.removeFromCache("standard1");
            //CacheUtil.removeFromCache("standard1max");
//            CacheUtil.putInCache("standard1",null);
            map0.put("car2Num", car2Num);
            map0.put("car2Type", car2Type);
            map0.put("repeat2", repeat2);
            LambdaQueryWrapper<TorqueStandards> torqueStandardsWrapper = new LambdaQueryWrapper<>();
            torqueStandardsWrapper.eq(TorqueStandards::getCarType, car2Type.trim());
            torqueStandardsWrapper.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition2);
            int count = torqueStandardsMapper.selectCount(torqueStandardsWrapper);
            if(count == 0){
                map0.put("standard2min", "");
                map0.put("standard2max", "");
                CacheUtil.removeFromCache("standard2");
                Map map1 = new HashMap();
                map1.put("message", "···工位二的扭力标准未设置\n无法保存螺丝数据··");
                String json1 = JSON.toJSONString(map1);
                webSocketServer.sendToAllClient(json1);
                //CacheUtil.removeFromCache("standard2max");
            } else if(count == 1) {
                TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsWrapper);
                CacheUtil.putInCache("standard2",torqueStandards);
                //CacheUtil.putInCache("standard2max",torqueStandards.getMaximumTorque());
                map0.put("standard2min", torqueStandards.getMinimumTorque().toString());
                map0.put("standard2max", torqueStandards.getMaximumTorque().toString());
//                String json = JSON.toJSONString(torqueStandards);
//                map0.put("standard2", json);
            }else {
                log.info("---工位二的扭力标准数据异常-----");
                map0.put("standard2min", "数据异常");
                map0.put("standard2max", "数据异常");
                CacheUtil.removeFromCache("standard2");
                //CacheUtil.removeFromCache("standard2max");
            }

            //把map转为json
            String json0 = JSON.toJSONString(map0);
//            log.info("车的json是"+json0);
            webSocketServer.sendToAllClient(json0);//推消息
            try {
//                Strand.sleep(frequencyProperties.getMonitorNodeFrequency());
                Thread.sleep(frequencyProperties.getMonitorNodeFrequency());
//                                    retrySubscribe();
            } catch (Exception e) {
                log.info(e.getMessage());
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
        } else if(!car1Num.isEmpty() &&
                !car1Type.isEmpty() &&
                !repeat1.isEmpty() &&
                car2Num.isEmpty() &&
                car2Type.isEmpty() &&
                repeat2.isEmpty()) {
            log.info("只是工位二没有数据，PLC不用重连");
            Map<String, String> map0 = new HashMap<>();
            map0.put("car1Num", car1Num);
            map0.put("car1Type", car1Type);
            map0.put("repeat1", repeat1);
            LambdaQueryWrapper<TorqueStandards> torqueStandardsWrapper = new LambdaQueryWrapper<>();
            torqueStandardsWrapper.eq(TorqueStandards::getCarType, car1Type.trim());
            torqueStandardsWrapper.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition1);
            int count = torqueStandardsMapper.selectCount(torqueStandardsWrapper);
            if(count == 0){
                map0.put("standard1min", "");
                map0.put("standard1max", "");
                CacheUtil.removeFromCache("standard1");
                Map map1 = new HashMap();
                map1.put("message", "···工位一的扭力标准未设置\n无法保存螺丝数据··");
                String json1 = JSON.toJSONString(map1);
                webSocketServer.sendToAllClient(json1);
                //CacheUtil.removeFromCache("standard1max");
            } else if(count == 1) {
                TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsWrapper);
                CacheUtil.putInCache("standard1",torqueStandards);
                //CacheUtil.putInCache("standard1max",torqueStandards.getMaximumTorque());
                map0.put("standard1min", String.valueOf(torqueStandards.getMinimumTorque()));
                map0.put("standard1max", String.valueOf(torqueStandards.getMaximumTorque()));
//                String json = JSON.toJSONString(torqueStandards);
//                map0.put("standard1", json);
            }else {
                log.info("---工位一的扭力标准数据异常-----");
                map0.put("standard1min", "数据异常");
                map0.put("standard1max", "数据异常");
                CacheUtil.removeFromCache("standard1");
                //CacheUtil.removeFromCache("standard1max");
            }

            map0.put("car2Num", "无数据");
            map0.put("car2Type",  "无数据");
            map0.put("repeat2",  "无数据");
            map0.put("standard2min",  "");
            map0.put("standard2max",  "");
            CacheUtil.removeFromCache("standard2");
            //CacheUtil.removeFromCache("standard2max");
//            CacheUtil.putInCache("standard2",null);
            //把map转为json
            String json0 = JSON.toJSONString(map0);
//            log.info("车的json是"+json0);
            webSocketServer.sendToAllClient(json0);//推消息
            try {
//                Strand.sleep(frequencyProperties.getMonitorNodeFrequency());
                Thread.sleep(frequencyProperties.getMonitorNodeFrequency());
//                                    retrySubscribe();
            } catch (Exception e) {
                log.info(e.getMessage());
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
        }
    }

    //优化后：



    //------------------------------------------
    //优化前：
    // 模拟发送数据到前端的函数
    //@Suspendable
    private Map<String, String> sendToFrontEnd(Map<NodeId, Object> monitoredValues) {// throws Exception   throws InterruptedException
        log.info("监控到的节点数据: " + monitoredValues);
        if(monitoredValues.isEmpty()){
            log.info("监控到空的节点数据");
            Map<String, String> map0 = new HashMap<>();
//            jSerialCommIOService.yellowUp();

            map0.put("car1Num", "OPC重连中");
            map0.put("car1Type", "OPC重连中");
            map0.put("repeat1", "OPC重连中");
            map0.put("standard1min", "");
            map0.put("standard1max", "");
            CacheUtil.removeFromCache("standard1");
            //CacheUtil.removeFromCache("standard1max");
            map0.put("car2Num", "OPC重连中");
            map0.put("car2Type", "OPC重连中");
            map0.put("repeat2", "OPC重连中");
            map0.put("standard2min", "");
            map0.put("standard2max", "");
            CacheUtil.removeFromCache("standard2");
            //CacheUtil.removeFromCache("standard2max");
            //把map转为json
            String json0 = JSON.toJSONString(map0);
            webSocketServer.sendToAllClient(json0);//推消息
            return null;
        }

        // 检查 monitoredValues 是否为 null
        String monitoredValuesStr = null; // 初始化为 null
//        if (monitoredValues != null) {
            monitoredValuesStr = monitoredValues.toString();

        String carTypeSuffix1 = carNodeProperties.getCarTypeSuffix1() != null ? carNodeProperties.getCarTypeSuffix1() : "";
        String carTypeSuffix2 = carNodeProperties.getCarTypeSuffix2() != null ? carNodeProperties.getCarTypeSuffix2() : "";
        String repeatSuffix1 = carNodeProperties.getRepeatSuffix1() != null ? carNodeProperties.getRepeatSuffix1() : "";
        String repeatSuffix2 = carNodeProperties.getRepeatSuffix2() != null ? carNodeProperties.getRepeatSuffix2() : "";
//        log.info("because s is null1");
        boolean containsNull1 = monitoredValues.toString().contains(carTypeSuffix1 + "}=null");
        boolean containsNull2 = monitoredValues.toString().contains(carTypeSuffix2 + "}=null");
        boolean containsNull3 = monitoredValues.toString().contains(repeatSuffix1 + "}=null");
        boolean containsNull4 = monitoredValues.toString().contains(repeatSuffix2 + "}=null");

//        log.info("carTypeSuffix12和repeatSuffix12分别是"+carTypeSuffix1+" "+carTypeSuffix2+" "
//                +repeatSuffix1+" "+repeatSuffix2);

        if ((containsNull1 && containsNull2 && containsNull3 && containsNull4)
                || (!monitoredValuesStr.contains(carTypeSuffix1) &&
                !monitoredValuesStr.contains(carTypeSuffix2) &&
                !monitoredValuesStr.contains(repeatSuffix1) &&
                !monitoredValuesStr.contains(repeatSuffix2))) {
            log.info("plc真断了？？？------------------");
            Map<String, String> map0 = new HashMap<>();
            map0.put("car1Num", "PLC已断开");
            map0.put("car1Type", "PLC已断开");
            map0.put("repeat1", "PLC已断开");
            map0.put("standard1min", "");
            map0.put("standard1max", "");
            CacheUtil.removeFromCache("standard1");
            //CacheUtil.removeFromCache("standard1max");
            map0.put("car2Num", "plc已断开");
            map0.put("car2Type", "plc已断开");
            map0.put("repeat2", "plc已断开");
            map0.put("standard2min", "");
            map0.put("standard2max", "");
            CacheUtil.removeFromCache("standard2");
            //CacheUtil.removeFromCache("standard2max");
            //把map转为json
            String json0 = JSON.toJSONString(map0);
//            log.info("plc已断开的json是"+json0);
            webSocketServer.sendToAllClient(json0);//推消息
            //蜂鸣器响5秒
            jSerialCommIOService.buzzerControl();
            try {
                // 挂起当前协程一段时间后重试
//                Strand.sleep(frequencyProperties.getMonitorNodeFrequency());
                Thread.sleep(frequencyProperties.getMonitorNodeFrequency());
            } catch (Exception e) {
//                log.info("睡眠问题？？？");
                log.info(e.getMessage());
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
            return null;
        }

        // 存储 carNum 和 carType 的列表
        List<String> carNumList = new ArrayList<>();
        List<String> carTypeList = new ArrayList<>();
        List<String> repeatList = new ArrayList<>();

// 遍历每一个 monitoredValues 的 entry
        for (Map.Entry<NodeId, Object> entry : monitoredValues.entrySet()) {
            String idString = entry.toString();
//            log.info("idString是"+idString);
            // 分类到相应的列表中MessageConstant.nodeNull+MessageConstant.carNum
            if (idString.startsWith(carNodeProperties.getNodeNull() + carNodeProperties.getCarNum())) {
                carNumList.add(idString); // 将 carNum ID 添加到列表MessageConstant.nodeNull+MessageConstant.carType
            } else if (idString.startsWith(carNodeProperties.getNodeNull() + carNodeProperties.getCarType())) {
                carTypeList.add(idString); // 将 carType ID 添加到列表MessageConstant.nodeNull+MessageConstant.repeat
            } else if (idString.startsWith(carNodeProperties.getNodeNull() + carNodeProperties.getRepeat())) {
                repeatList.add(idString); // 将 repeat ID 添加到列表
            }else {
                log.info("idString是"+idString);
            }
        }
        Map<String, String> carTypeMap = process(carTypeList);
        List<String> carTypeMap1 = Collections.singletonList(carTypeMap.get("asciiBuilder1"));
        List<String> carTypeMap2 = Collections.singletonList(carTypeMap.get("asciiBuilder2"));
        Map<String, String> repeatMap = process(repeatList);
        List<String> repeatMap1 = Collections.singletonList(repeatMap.get("asciiBuilder1"));
        //List<String> repeatMap2 = Collections.singletonList(repeatMap.get("asciiBuilder2"));//工位二的连番直接拿工位一的-3

//        String car1Num = carNumMap1.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
//        String car2Num = carNumMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
        String car1Num = null;
        String car2Num = null;
        String car1Type = carTypeMap1.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
        String car2Type = carTypeMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
        String repeat1 = repeatMap1.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
//        String repeat2 = repeatMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");//工位二的连番直接拿工位一的-3

// 定义repeat2，默认值可根据业务需求调整
        String repeat2 = "";
//        try {
//            // 将repeat1转换为整数，减3后再转为字符串
//            int repeat1Int = Integer.parseInt(repeat1.trim()); // 去除可能的空格
//            //防止减到负数
//            if(repeat1Int >= 3) {
//                repeat2 = String.valueOf(repeat1Int - 3);
//            }else if(repeat1Int == 2){
//                repeat2 = "99";
//            }else if(repeat1Int == 1){
//                repeat2 = "98";
//            }else if(repeat1Int == 0){
//                repeat2 = "97";
//            }
//        } catch (NumberFormatException e) {
//            // 处理转换失败的情况（比如repeat1不是有效数字）
//            // 可根据业务需求设置默认值或抛出异常
//            log.info("repeat1格式错误，无法转换为整数: " + repeat1);
//            repeat2 = ""; // 或其他默认值
//        }

        if(repeat1.length() == 1){
            repeat1 = "0"+repeat1;
        }

//        if(repeat2.length() == 1){
//            repeat2 = "0"+repeat2;
//        }

        if(car1Type.equals(carTypeProperties.getCamryOriginal1())){
            car1Type = carTypeProperties.getCamry();
        }else if (car1Type.equals(carTypeProperties.getLevinOriginal1())) {
            car1Type = carTypeProperties.getLevin();
        }else {
            car1Type = "未知车型";
        }

//        if(car2Type.equals(carTypeProperties.getCamryOriginal2())){
//            car2Type = carTypeProperties.getCamry();
//        }else if(car2Type.equals(carTypeProperties.getLevinOriginal2())){
//            car2Type = carTypeProperties.getLevin();
//        }else {
//            car2Type = "未知车型";
//        }

        Object fourTimes = CacheUtil.getFromCache("4times");
        int fourTimesInt = 0;
        if(fourTimes != null){
            fourTimesInt = Integer.parseInt(fourTimes.toString().trim());
        }

        //刚开软件时，工位二先读取四次盘
        if(fourTimesInt > 0){
            //读取四次盘
            List<String> repeatMap2 = Collections.singletonList(repeatMap.get("asciiBuilder2"));//工位二的连番直接拿工位一的-3
            repeat2 = repeatMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");//工位二的连番直接拿工位一的-3

            if(repeat2.length() == 1){
                repeat2 = "0"+repeat2;
            }

            car2Type = carTypeMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
            if(car2Type.equals(carTypeProperties.getCamryOriginal2())){
                car2Type = carTypeProperties.getCamry();
            }else if(car2Type.equals(carTypeProperties.getLevinOriginal2())){
                car2Type = carTypeProperties.getLevin();
            }else {
                car2Type = "未知车型";
            }

            List<Integer> RepeatNum = getLatest4CarRepeatNumsByPosition (MessageConstant.workingPosition1);

            int car12RepeatNum = RepeatNum.get(0);
            int car22RepeatNum = RepeatNum.get(1);
            int car32RepeatNum = RepeatNum.get(2);
            int car42RepeatNum = RepeatNum.get(3);

            CarNumPrefix carNumPrefix2 = getCarNumPrefix2();

//                      Object carNum1 = CacheUtil.getFromCache("carNum1");
//                      String carNum1String = carNum1 != null ? String.valueOf(carNum1) : "";
//                      log.info(carNum1 + "当前缓存carNum1是" + carNum1String);

            //前四次需要拿出缓存更新从盘里读到的carNum拼接后的数据
            Object carNum2 = CacheUtil.getFromCache("carNum2");
            String carNum2String = carNum2 != null ? String.valueOf(carNum2) : "";
            log.info(carNum2 + "读盘-当前缓存carNum2是" + carNum2String);

            Object repeat2cache = CacheUtil.getFromCache("repeat2");
            String repeat2String = repeat2cache != null ? String.valueOf(repeat2cache) : "";
            log.info("读盘-当前缓存repeat2String是" + repeat2String);

            //TODO 读盘拼接车身号 repeat2是刚刚读到的，repeat2String是上一次缓存下来的
            car2Num = handleCar2NumLogic(repeat2, repeat2String, carNum2String,
                    car12RepeatNum,car22RepeatNum,car32RepeatNum,car42RepeatNum,carNumPrefix2);

            //不应该更新上一次存下来的车2连番信息，因为会导致后面进不去那个保存车2的信息的逻辑了
            CacheUtil.putInCache("carNum2",car2Num);//已经拼接过的车身号
//            CacheUtil.putInCache("carType2",car2Type);
//            CacheUtil.putInCache("repeat2",repeat2);

            //当连番变化时，才算一次读盘
            if(!repeat2.trim().equals(repeat2String) &&
                    !repeat2.trim().isEmpty()
                    || repeat2String.trim().isEmpty()){
//                save(car);
                //减去一次
                fourTimesInt--;
                CacheUtil.putInCache("4times", fourTimesInt);
            }
        }else {
            //四次盘读完了，开始读取数据库倒数第四条，就不需要拼接了
              LambdaQueryWrapper<Car> carLambdaQueryWrapper = new LambdaQueryWrapper<>();
              // 先查询数据库信息的总条数
              int count = carMapper.selectCount(carLambdaQueryWrapper);

              Car targetCar;
              if (count >= 3) {
                  log.info("记录数>=3");
                  // 只有当记录数 >=4 时，才查询倒数第4条，工位二存的车信息就不再搅合进来了
                  carLambdaQueryWrapper.eq(Car::getWorkingPositionId, MessageConstant.workingPosition1)
                          .orderByDesc(Car::getCreateTime)
                          .last("LIMIT 2, 1");//"LIMIT 3, 1"
                  targetCar = carMapper.selectOne(carLambdaQueryWrapper);

                  //缓存起来工位二的上一辆车信息//不能在这里写，因为在这里的后面立即就get了，会导致每次都报警，写在报警之后再更新缓存才对
//                  CacheUtil.putInCache("lastCar2",targetCar);
                  //先把现在的车存起来，后面报警完之后再获取并更新缓存lastCar2
                  log.info("更新了工位二上一辆车的信息"+targetCar);
                  CacheUtil.putInCache("targetCar",targetCar);

                  repeat2 = targetCar.getRepeatNum();
                  car2Type = targetCar.getCarType();
                  car2Num = targetCar.getCarId();
                  //读到后直接推入缓存
                  //不应该更新上一次存下来的车2连番信息，因为会导致后面进不去那个保存车2的信息的逻辑了
                  CacheUtil.putInCache("carNum2",car2Num);//其实是已经拼接过的车身号，在工位一拼接的
//                  CacheUtil.putInCache("carType2",car2Type);
//                  CacheUtil.putInCache("repeat2",repeat2);

                  if(car2Num.length() > 2) {
                      //需要立即更新工位二的车身号前缀，否则工位二的车身号前缀无法更新(只在刚打开软件读三次盘并且是刚好99到0这个区间才会更新，概率太小了)
                      CarNumPrefix carNumPrefix2 = getCarNumPrefix2();
                      //去掉car2Num里的最后两位是repeat2的，剩下的就是工位二的车身号前缀
                      String car2NumStr = car2Num.substring(0, car2Num.length() - 2);
                      log.info("更新的carNumPrefix2缓存,截取到的车身号前缀是" + car2NumStr);
                      //有变化才更新，避免一直操作数据库
                      if (!carNumPrefix2.getCarNum().equals(car2NumStr)) {
                          carNumPrefix2.setCarNum(car2NumStr);
                          carNumPrefixMapper.updateById(carNumPrefix2);
                          CacheUtil.putInCache("carNumPrefix2", car2NumStr);
                      }
                  }
              } else {
                  // 处理记录不足4条的情况（如返回null、默认值等）
//                  log.info("符合条件的记录不足4条，直接拿工位一的-3/读盘信息");
                  log.info("符合条件的记录不足3条，直接拿工位一的-2/读盘信息");

                  try {
                      // 将repeat1转换为整数，减3后再转为字符串
                      int repeat1Int = Integer.parseInt(repeat1.trim()); // 去除可能的空格
                      //防止减到负数
//                      if(repeat1Int >= 3) {
//                          repeat2 = String.valueOf(repeat1Int - 3);
//                      }else if(repeat1Int == 2){
//                          repeat2 = "99";
//                      }else if(repeat1Int == 1){
//                          repeat2 = "98";
//                      }else if(repeat1Int == 0){
//                          repeat2 = "97";
//                      }

                      if(repeat1Int >= 2) {
                          repeat2 = String.valueOf(repeat1Int - 2);
                      }else if(repeat1Int == 1){
                          repeat2 = "99";
                      }else if(repeat1Int == 0){
                          repeat2 = "98";
                      }

                      if(repeat2.length() == 1){
                        repeat2 = "0"+repeat2;
                      }

                      car2Type = car1Type;

                      //TODO 读工位一信息拼接车身号，没法弄
                      //因为数据库数据小于4条，所以拿的工位一的车身号是没问题的，100条数据才开始+1
                      car1Num = (String) CacheUtil.getFromCache("carNum1");
                      car2Num = car1Num;//"暂无车信息";//直接给个空算了

                  } catch (NumberFormatException e) {
                      // 处理转换失败的情况（比如repeat1不是有效数字）
                      // 可根据业务需求设置默认值或抛出异常
                      log.info("repeat1格式错误，无法转换为整数，改成读盘...: " + repeat2);
                      List<String> repeatMap2 = Collections.singletonList(repeatMap.get("asciiBuilder2"));//工位二的连番直接拿工位一的-3
                      repeat2 = repeatMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");//工位二的连番直接拿工位一的-3

                      if(repeat2.length() == 1){
                          repeat2 = "0"+repeat2;
                      }

                      car2Type = carTypeMap2.toString().replaceAll("^[\\[\\s]+|[\\]\\s]+$", "");
                      if(car2Type.equals(carTypeProperties.getCamryOriginal2())){
                          car2Type = carTypeProperties.getCamry();
                      }else if(car2Type.equals(carTypeProperties.getLevinOriginal2())){
                          car2Type = carTypeProperties.getLevin();
                      }else {
                          car2Type = "未知车型";
                      }

                      List<Integer> RepeatNum = getLatest4CarRepeatNumsByPosition (MessageConstant.workingPosition1);

                      int car12RepeatNum = RepeatNum.get(0);
                      int car22RepeatNum = RepeatNum.get(1);
                      int car32RepeatNum = RepeatNum.get(2);
                      int car42RepeatNum = RepeatNum.get(3);

                      CarNumPrefix carNumPrefix2 = getCarNumPrefix2();

//                      Object carNum1 = CacheUtil.getFromCache("carNum1");
//                      String carNum1String = carNum1 != null ? String.valueOf(carNum1) : "";
//                      log.info(carNum1 + "当前缓存carNum1是" + carNum1String);

                      Object carNum2 = CacheUtil.getFromCache("carNum2");
                      String carNum2String = carNum2 != null ? String.valueOf(carNum2) : "";
                      log.info(carNum2 + "读盘-当前缓存carNum2是" + carNum2String);

                      Object repeat2cache = CacheUtil.getFromCache("repeat2");
                      String repeat2String = repeat2cache != null ? String.valueOf(repeat2cache) : "";
                      log.info("读盘-当前缓存repeat2String是" + repeat2String);

                      //TODO 读盘拼接车身号 repeat2是刚刚读到的，repeat2String是上一次缓存下来的
                      car2Num = handleCar2NumLogic(repeat2, repeat2String, carNum2String,
                      car12RepeatNum,car22RepeatNum,car32RepeatNum,car42RepeatNum,carNumPrefix2);
                  }

                  //不能写，因为后面自然会存的，写了之后反而会导致后面的（当前读到的数据和上一次留下来的数据做对比）有影响
                  //不应该更新上一次存下来的车2信息，因为会导致后面进不去那个保存车2的信息的逻辑了
                  CacheUtil.putInCache("carNum2",car2Num);//车身号可以提前更新到缓存，因为carNum1在后面也拼接+1并更新了
//                  CacheUtil.putInCache("carType2",car2Type);
//                  CacheUtil.putInCache("repeat2",repeat2);
              }

        }

        //-----------------------------------------------

        log.info("车1车型是"+car1Type+"连番"+repeat1);
        log.info("车2车型是"+car2Type+"连番"+repeat2);

        //应该在这里处理
//        LocalDate today = LocalDate.now();
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        //今天
//        String todayStr = today.format(formatter);
        //昨天
//        String yesterdayStr = today.minusDays(1).format(formatter);

//        String yymmdd = formatToYYMMDD(todayStr);
//        String yymmdd0 = formatToYYMMDD(yesterdayStr);
//        CacheUtil.putInCache("yymmdd",yymmdd);
//        CacheUtil.putInCache("yymmdd0",yymmdd0);
//        log.info("今天是"+yymmdd);

        LambdaQueryWrapper<CarNumPrefix> queryWrapper = new LambdaQueryWrapper<>();
//        LambdaQueryWrapper<CarNumPrefix> queryWrapperYes = new LambdaQueryWrapper<>();
//        LambdaQueryWrapper<CarNumPrefix> queryWrapper2 = new LambdaQueryWrapper<>();
//        LambdaQueryWrapper<CarNumPrefix> queryWrapperYes2 = new LambdaQueryWrapper<>();

//        log.info("todayStr是："+todayStr);
//        queryWrapper.like(CarNumPrefix::getCreateTime, todayStr);
        queryWrapper.eq(CarNumPrefix::getWorkingPositionId, MessageConstant.workingPosition1);

//        queryWrapper2.like(CarNumPrefix::getCreateTime, todayStr);
//        queryWrapper2.eq(CarNumPrefix::getWorkingPositionId, MessageConstant.workingPosition2);

//        queryWrapperYes.like(CarNumPrefix::getCreateTime, yesterdayStr);
//        queryWrapperYes.eq(CarNumPrefix::getWorkingPositionId, MessageConstant.workingPosition1);

//        queryWrapperYes2.like(CarNumPrefix::getCreateTime, yesterdayStr);
//        queryWrapperYes2.eq(CarNumPrefix::getWorkingPositionId, MessageConstant.workingPosition2);

//        int carNumPrefixCount = carNumPrefixMapper.selectCount(queryWrapper);
        List<CarNumPrefix> carNumPrefixCount = carNumPrefixMapper.selectList(queryWrapper);

//        log.info("carNumPrefixCount是"+carNumPrefixCount);
//        int carNumPrefixCountYes = carNumPrefixMapper.selectCount(queryWrapperYes);

//        int carNumPrefixCount2 = carNumPrefixMapper.selectCount(queryWrapper2);
//        int carNumPrefixCountYes2 = carNumPrefixMapper.selectCount(queryWrapperYes2);
//        log.info("carNumPrefixCount2是"+carNumPrefixCount2);

        //获取工位一的车身号前缀
        CarNumPrefix carNumPrefix = new CarNumPrefix();
        if(carNumPrefixCount.size() == 1){
            carNumPrefix = carNumPrefixMapper.selectOne(queryWrapper);
            //其它地方需要调用
            if (carNumPrefix != null && carNumPrefix.getCarNum() != null) {
                CacheUtil.putInCache("carNumPrefix", carNumPrefix.getCarNum().trim());
            }
        }else if(carNumPrefixCount.size() > 1){
            log.info("数据库存在多个车身号前缀，取第一个");
            carNumPrefix = carNumPrefixCount.get(0);
//            Map map = new HashMap();
//            try {
//                Thread.sleep(12000);
//            } catch (InterruptedException e) {
//                log.info(e.getMessage());
//                e.printStackTrace();
//            }
//            map.put("message", "..存在多个车身号前缀，请联系管理员..");
//            String json = JSON.toJSONString(map);
//            webSocketServer.sendToAllClient(json);
        }else {
            carNumPrefix = null;
        }

        //获取工位二的车身号前缀
//        CarNumPrefix carNumPrefix2 = new CarNumPrefix();
//        if(carNumPrefixCount2 == 1){
//            carNumPrefix2 = carNumPrefixMapper.selectOne(queryWrapper2);
//            log.info("carNumPrefix2是"+carNumPrefix2);
//            //其它地方需要调用
//            if (carNumPrefix2 != null && carNumPrefix2.getCarNum() != null) {
//                CacheUtil.putInCache("carNumPrefix2", carNumPrefix2.getCarNum().trim());
//            }
//        }else if(carNumPrefixCount2 > 1){
//            log.info("数据库存在多个车身号前缀");
//            Map map = new HashMap();
//            try {
//                Thread.sleep(12000);
//            } catch (InterruptedException e) {
//                log.info(e.getMessage());
//                e.printStackTrace();
//            }
//            map.put("message", "..存在多个车身号前缀，请联系管理员..");
//            String json = JSON.toJSONString(map);
//            webSocketServer.sendToAllClient(json);
//        }else {
//            carNumPrefix2 = null;
//        }

                log.info("用数据库的车身号前缀");
                //用数据库里的前缀和连番进行拼接，构建车身号
//                try {
                    //TODO 假如i.get("repeat1").trim()是01，repeat1会变成1
                    int repeat1Int = -1;
                    if (!repeat1.trim().isEmpty() && repeat1.trim().matches("-?\\d+")) {
                        log.info("repeat1是数字" + repeat1);
                        repeat1Int = Integer.parseInt(repeat1.trim());
                    } else {
                        log.info("repeat1不是数字");
                        try {
                            Thread.sleep(12000);
                        } catch (InterruptedException e) {
                            log.info(e.getMessage());
                            e.printStackTrace();
                        }
                        Map map = new HashMap();
                        map.put("message", "..门铰链工位的连番必须是数字..");
                        String json = JSON.toJSONString(map);
                        webSocketServer.sendToAllClient(json);
                    }

//                    int repeat2Int = -1;
//                    if (!repeat2.trim().isEmpty() && repeat2.trim().matches("-?\\d+")) {
////                        log.info("repeat2是数字" + repeat2);
//                        repeat2Int = Integer.parseInt(repeat2.trim());
//                    } else {
//                        log.info("repeat2不是数字");
//                        try {
//                            Thread.sleep(12000);
//                        } catch (InterruptedException e) {
//                            log.info(e.getMessage());
//                            e.printStackTrace();
//                        }
//                        Map map = new HashMap();
//                        map.put("message", "..发动机盖工位的连番必须是数字..");
//                        String json = JSON.toJSONString(map);
//                        webSocketServer.sendToAllClient(json);
//                    }

                    List<Integer> RepeatNum = getLatest4CarRepeatNumsByPosition (MessageConstant.workingPosition1);
                    int car1RepeatNum = RepeatNum.get(0);
                    int car2RepeatNum = RepeatNum.get(1);
                    int car3RepeatNum = RepeatNum.get(2);
                    int car4RepeatNum = RepeatNum.get(3);

                    //获取数据库最新四辆车信息改造前：
//                    LambdaQueryWrapper<Car> queryCarWrapper = new LambdaQueryWrapper<>();
////                    LambdaQueryWrapper<Car> queryCarWrapper2 = new LambdaQueryWrapper<>();
//                    // 根据创建时间排序
////                    queryCarWrapper.eq(Car::getWorkingPositionId,MessageConstant.workingPosition1);
////                    queryCarWrapper2.eq(Car::getWorkingPositionId,MessageConstant.workingPosition2);
//                    // 根据创建时间排序
//                    queryCarWrapper.orderByDesc(Car::getCreateTime);
////                    queryCarWrapper2.orderByDesc(Car::getCreateTime);
//                    // 使用 last 方法添加 LIMIT 3
//                    queryCarWrapper.last("LIMIT 4");
////                    queryCarWrapper2.last("LIMIT 4");
////                    queryCarWrapper.last("LIMIT 3");
////                    queryCarWrapper2.last("LIMIT 3");
//        //为什么注释掉
////                    queryCarWrapper.eq(Car::getWorkingPositionId, MessageConstant.workingPosition1);
////                    queryCarWrapper2.eq(Car::getWorkingPositionId, MessageConstant.workingPosition2);
//                    List<Car> carList = carMapper.selectList(queryCarWrapper);
////                    List<Car> carList2 = carMapper.selectList(queryCarWrapper2);
//                    log.info("取最新四条");
//                    Car car1 = new Car();
////                    Car car12 = new Car();
//                    if (!carList.isEmpty()) {
//                        car1 = carList.get(0);
////                        log.info("car1是" + car1);
//                    }
////                    if (!carList2.isEmpty()) {
////                        car12 = carList2.get(0);
//////                        log.info("car12是" + car12);
////                    }
//
//                    Car car2 = new Car();
////                    Car car22 = new Car();
//                    if (carList.size() >= 2) {
//                        car2 = carList.get(1);
////                        log.info("car2是" + car2);
//                    }
////                    if (carList2.size() >= 2) {
////                        car22 = carList2.get(1);
//////                        log.info("car22是" + car22);
////                    }
//
//                    Car car3 = new Car();
////                    Car car32 = new Car();
//                    if (carList.size() >= 3) {
//                        car3 = carList.get(2);
////                        log.info("car3是" + car3);
//                    }
////                    if (carList2.size() >= 3) {
////                        car32 = carList2.get(2);
//////                        log.info("car32是" + car32);
////                    }
//
//                    Car car4 = new Car();
////                    Car car42 = new Car();
//                    if (carList.size() >= 4) {
//                        car4 = carList.get(3);
////                        log.info("car3是" + car3);
//                    }
////                    if (carList2.size() >= 4) {
////                        car42 = carList2.get(3);
//////                        log.info("car32是" + car32);
////                    }
//
//                    int car1RepeatNum = Optional.ofNullable(car1.getRepeatNum())
//                            .map(Integer::parseInt)
//                            .orElse(-1); // 提供默认值
////                    int car12RepeatNum = Optional.ofNullable(car12.getRepeatNum())
////                            .map(Integer::parseInt)
////                            .orElse(-1); // 提供默认值
//
//                    int car2RepeatNum = Optional.ofNullable(car2.getRepeatNum())
//                            .map(Integer::parseInt)
//                            .orElse(-1); // 提供默认值
////                    int car22RepeatNum = Optional.ofNullable(car22.getRepeatNum())
////                            .map(Integer::parseInt)
////                            .orElse(-1); // 提供默认值
//
//                    int car3RepeatNum = Optional.ofNullable(car3.getRepeatNum())
//                            .map(Integer::parseInt)
//                            .orElse(-1); // 提供默认值
////                    int car32RepeatNum = Optional.ofNullable(car32.getRepeatNum())
////                            .map(Integer::parseInt)
////                            .orElse(-1); // 提供默认值
//
//                    int car4RepeatNum = Optional.ofNullable(car4.getRepeatNum())
//                            .map(Integer::parseInt)
//                            .orElse(-1);
////                    int car42RepeatNum = Optional.ofNullable(car42.getRepeatNum())
////                            .map(Integer::parseInt)
////                            .orElse(-1);



                    Object carNum1 = CacheUtil.getFromCache("carNum1");
                    String carNum1String = carNum1 != null ? String.valueOf(carNum1) : "";
                    log.info(carNum1 + "当前缓存carNum1是" + carNum1String);
//从缓存里拿出carNum来是为了拼接和+1，拼接完和+1完之后还要重新放回缓存里
//                    Object carNum2 = CacheUtil.getFromCache("carNum2");
//                    String carNum2String = carNum2 != null ? String.valueOf(carNum2) : "";
//                    log.info(carNum2 + "当前缓存carNum2是" + carNum2String);

        //工位二除了前四次，后面都不需要拼接

//                    //构建car2Num，省去了拼接和+1
//                    if(carNum2String != null && !carNum2String.isEmpty()){
//                        car2Num = carNum2String.trim();
//                    }
//                    //只有车身号可以提前存入缓存？？？？因为后面判断变化的值都是repeat
//                    CacheUtil.putInCache("carNum2",car2Num.trim());

                    Object repeat1cache = CacheUtil.getFromCache("repeat1");
                    String repeat1String = repeat1cache != null ? String.valueOf(repeat1cache) : "";
                    log.info("当前缓存repeat1String是" + repeat1String);

                    Object repeat2cache = CacheUtil.getFromCache("repeat2");
                    String repeat2String = repeat2cache != null ? String.valueOf(repeat2cache) : "";
                    log.info("当前缓存repeat2String是" + repeat2String);


                    //数据库最新三条(排除掉不连续得插入车型（显示***repeat，保存以HH-MM-SS-repeat）)

                    //TODO 判断连续，如果判断是了，就拼接日期，否则拼接下面的拼接逻辑  //TODO 只需要判断工位一的连番是否连续
//                    int a;
//                    int b;
//                    int c;
//                    if(repeat1Int == 0){
//                        a = 99;
//                        b = 98;
//                        c = 97;
//                    }else if(repeat1Int == 1){
//                        a = 0;
//                        b = 99;
//                        c = 98;
//                    }else if(repeat1Int == 2){
//                        a = 1;
//                        b = 0;
//                        c = 99;
//                    }else {
//                        a = repeat1Int - 1;
//                        b = repeat1Int - 2;
//                        c = repeat1Int - 3;
//                    }
        //优化：
//        Math.floorMod(x, 100) 的作用是：对 x 进行模 100 运算，且结果始终为非负数（即使 x 是负数）：
//        当 x >= 0 时，结果就是 x % 100（例如 3 % 100 = 3）
//        当 x < 0 时，结果是 100 + (x % 100)（例如 -1 % 100 = 99，-2 % 100 = 98）
                    int a = Math.floorMod(repeat1Int - 1, 100);
                    int b = Math.floorMod(repeat1Int - 2, 100);
                    int c = Math.floorMod(repeat1Int - 3, 100);
                    log.info("repeat1Int是{}，a是{}b是{}c是{}",repeat1Int,a,b,c);
//                    System.out.printf("repeat1Int是%s，a是%s，b是%s，c是%s%n", repeat1Int, a, b, c);
//                    System.out.println("RepeatNum是:"+RepeatNum);
        // 检查列表中是否包含a、b、c中的任意一个（需先判断列表非空，避免空指针）
                    boolean shouldConcat = false;//默认是不连续的

//        // 1. 先单独判断并存储三个条件的结果（避免重复计算，且便于打印）
//        boolean containsA = false;
//        boolean containsB = false;
//        boolean containsC = false;
//
//// 先判断RepeatNum是否为空，避免NullPointerException
//        if (!RepeatNum.isEmpty()) {
//            containsA = RepeatNum.contains(a);
//            containsB = RepeatNum.contains(b);
//            containsC = RepeatNum.contains(c);
//        }
//
//// 2. 打印三个条件各自的结果（核心需求）
//        log.info("单独条件判断结果：");
//        log.info("RepeatNum.contains(a) = {}", containsA); // 打印a的判断结果
//        log.info("RepeatNum.contains(b) = {}", containsB); // 打印b的判断结果
//        log.info("RepeatNum.contains(c) = {}", containsC); // 打印c的判断结果


        log.info("RepeatNum是:"+RepeatNum);
                    if (!RepeatNum.isEmpty()) {//4times
                            shouldConcat =
                            RepeatNum.contains(a)
                            || RepeatNum.contains(b)
                            || RepeatNum.contains(c);//其中一个成立，则认为是连续的
                        log.info("其中一个成立，则认为是连续的");
                        //突然打开软件，前三个隔了很远录入的数据都判断不了是连续的，后面的数据就会全部都是不连续的
//                        if(!RepeatNum.contains(a)
//                                && !RepeatNum.contains(b)
//                                && !RepeatNum.contains(c)){
//                            log.info("一个都不成立，前三个-都-是不连续的");
//                            //解决：如果前三个都是不连续的，就默认把当前读到的当作是连续的
//                            shouldConcat = true;//如果全部不成立，则认为是连续的
//                        }
                    }//save(car fourTimesInt > 0  无论如何都是连续的了。。。。。

                    log.info("shouldConcat是" + shouldConcat);
                    log.info("fourTimesInt是" + fourTimesInt);
        //fourTimesInt初始是4，上面减了一次1，当减到0时，才会进入连续判断，相当于前三次直接认为是连续的，第四次才开始判断是否是连续
        // 若没有一个成立，则拼接时间格式（HH-MM-SS-）
        //若 fourTimesInt > 0，是软件刚打开的前三次，直接不判断，直接认为是连续的走else端， fourTimesInt <= 0，才能进去判断是否需要拼接
                    if (!shouldConcat && fourTimesInt <= 0) {//shouldConcat=true,连续，shouldConcat=false,不连续
                        log.info("连番是---不连续的");
                        //连番变化时才拼接
                        if(!repeat1.trim().equals(repeat1String) &&
                                !repeat1.trim().isEmpty() ||
                                repeat1String.trim().isEmpty()) {
                            // 格式化当前时间为HH-MM-SS
                            SimpleDateFormat sdf = new SimpleDateFormat("HH-mm-ss");
                            String timePrefix = sdf.format(new Date()) + "-";
                            CacheUtil.putInCache("timePrefix", timePrefix);
                            // 拼接结果
                            car1Num = timePrefix + repeat1;
                            System.out.println("不连续连番拼接结果:" + car1Num);
                            log.info("不连续拼接结果:" + car1Num);
                        }else {
                            car1Num = carNum1String.trim();
                            CacheUtil.putInCache("carNum1",car1Num.trim());
                            System.out.println("不连续1连番拼接过了:" + car1Num);
                            log.info("不连续1连番拼接过了"+car1Num);
                        }
                    }else {
                    //否则正常拼接
                    log.info("连番是--连续的");

                    //应该是连番有改变时才放行 &&
//                            !repeat1.trim().isEmpty() && !repeat1String.isEmpty()
//-------------------------处理car1Num的车身号前缀加1和拼接问题
        //构建car1Num
                    log.info("repeat1是"+repeat1);
                    if (!repeat1.trim().equals(repeat1String) &&
                            !repeat1.trim().isEmpty() ||
                            repeat1String.trim().isEmpty())
                    {
                        log.info("当前1连番是："+repeat1+"上一个连番是："+repeat1String);

//                        Object allowPlus1 = CacheUtil.getFromCache("allowPlus1");

                        LambdaQueryWrapper<allowPlus> allowPlusLambdaQueryWrapper = new LambdaQueryWrapper<>();
                        allowPlusLambdaQueryWrapper.eq(allowPlus::getId, 1);//这个表只有一条
                        allowPlus allowPlus1SQl = allowPlusMapper.selectOne(allowPlusLambdaQueryWrapper);
                        int allowPlus1Int = 0;
                        if(allowPlus1SQl != null){
                            allowPlus1Int = allowPlus1SQl.getAllowPlus1();
                            //不能小于0
                            if(allowPlus1Int > 0) {
                                allowPlus1Int = (allowPlus1Int - 1);
//                                CacheUtil.putInCache("allowPlus1", allowPlus1Int);
                                allowPlus1SQl.setAllowPlus1(allowPlus1Int);
                                allowPlusMapper.updateById(allowPlus1SQl);
                            }
                        }else {//用缓存兜底
                            Object allowPlus1 = CacheUtil.getFromCache("allowPlus1");
                            if (allowPlus1 != null) {
                                //不能小于0
                                allowPlus1Int = (Integer.parseInt(allowPlus1.toString()));
                                if (allowPlus1Int > 0) {
                                    allowPlus1Int = (allowPlus1Int - 1);
                                    CacheUtil.putInCache("allowPlus1", allowPlus1Int);
                                }
                            }
                        }

                        log.info(repeat1Int+"repeat1Int和allowPlus1Int是"+allowPlus1Int);
                        if ((repeat1Int == 0 || repeat1Int == 1 || repeat1Int == 2
                                || repeat1Int == 3 || repeat1Int == 4 || repeat1Int == 5)
                                && !repeat1String.isEmpty()) {
                            //连番经过了一个轮回，车身号前缀 + 1 然后拼接
                            if (allowPlus1Int == 0 &&
                                    ((car1RepeatNum == 99 || car1RepeatNum == 98 || car1RepeatNum == 97 || car1RepeatNum == 96)
                                    || (car2RepeatNum == 99 || car2RepeatNum == 98 || car2RepeatNum == 97 || car2RepeatNum == 96)
                                    || (car3RepeatNum == 99 || car3RepeatNum == 98 || car3RepeatNum == 97 || car3RepeatNum == 96)
                                    || (car4RepeatNum == 99 || car4RepeatNum == 98 || car4RepeatNum == 97 || car4RepeatNum == 96)))
                            {
                                log.info("工位1连番经过了一个轮回，车身号 + 1");

                                //清0时，才允许+1，这里重置为10
                                if (allowPlus1SQl != null) {
                                    allowPlus1SQl.setAllowPlus1(10);
                                    allowPlusMapper.updateById(allowPlus1SQl);
                                }else {
                                    //清0时，才允许+1，这里重置为10
                                    CacheUtil.putInCache("allowPlus1", 10);
                                }

                                if (carNumPrefix != null && carNumPrefix.getCarNum() != null) {
                                    int carNum = NumberUtils.toInt(carNumPrefix.getCarNum(), 0);
                                    car1Num = (carNum + 1) + repeat1.trim();
//                                    car1Num = (Integer.parseInt(carNumPrefix.getCarNum()) + 1) + repeat1.trim();
                                    //更新carNum1缓存
                                    CacheUtil.putInCache("carNum1",car1Num.trim());
                                }else {
                                    Map map = new HashMap();
                                    map.put("message",".车门铰链的车身号前缀未设置.");
                                    String json = JSON.toJSONString(map);
                                    webSocketServer.sendToAllClient(json);
                                }

                                //更新工位一的车身号前缀
                                if (carNumPrefix != null && carNumPrefix.getCarNum() != null) {
                                    carNumPrefix.setCarNum(String.valueOf(Integer.parseInt(carNumPrefix.getCarNum()) + 1));
                                    //XXXXX更新缓存(不用更新这个前缀的缓存，因为更新了数据库，上面在获取数据库数据的时候会一直更新这个前缀的缓存)
                                    log.info("更新的carNumPrefix缓存是"+(Integer.parseInt(carNumPrefix.getCarNum()) + 1));
                                    CacheUtil.putInCache("carNumPrefix",(Integer.parseInt(carNumPrefix.getCarNum())));
                                }
                                //同时也要更新工位二的(如果已经走完四格之后)
                                //TODO 不应该在这里更新，应该是工位二读到数据库前四条数据是什么，就立即更新到工位二的车身号前缀

                                carNumPrefixMapper.updateById(carNumPrefix);
//                                log.info("car1Num是"+car1Num);
                                //更新carNum1缓存
//                                CacheUtil.putInCache("carNum1",car1Num.trim());
                            }else {//当前连番是012，但是前三个都不是99，98，97，不用 + 1，但是也需要拼接
                                log.info("当前连番是012，连番正常拼接"+carNumPrefix);
                                if (carNumPrefix != null) {
                                    car1Num = carNumPrefix.getCarNum() + repeat1.trim();
                                }else {
                                    car1Num = "null" + repeat1.trim();
                                    Map map = new HashMap();
                                    map.put("message",".车门铰链的车身号前缀未设置.");
                                    String json = JSON.toJSONString(map);
                                    webSocketServer.sendToAllClient(json);
                                }
//                                log.info("car1Num是" + car1Num);
                                //更新carNum1缓存
                                CacheUtil.putInCache("carNum1", car1Num.trim());
                            }
                        } else if (repeat1Int == -1) {//1.repeat1Int未获取到，2.初始??
                            log.info("repeat1未获取到，不处理");
//                        car1Num = carNumPrefix.getCarNum() + repeat1Int + 1;
                        } else {//连番 + 1 再拼接
                            log.info("连番正常拼接"+carNumPrefix);
                            if (carNumPrefix != null) {
                                car1Num = carNumPrefix.getCarNum() + repeat1.trim();
                            }else {
                                car1Num = "null" + repeat1.trim();
                                Map map = new HashMap();
                                map.put("message",".车门铰链的车身号前缀未设置.");
                                String json = JSON.toJSONString(map);
                                webSocketServer.sendToAllClient(json);
                            }
//                            log.info("car1Num是" + car1Num.trim());
                            //更新carNum1缓存
                            CacheUtil.putInCache("carNum1", car1Num.trim());
                        }
                    }else {
                        car1Num = carNum1String.trim();
                        CacheUtil.putInCache("carNum1",car1Num.trim());
                        log.info("1连番拼接过了"+car1Num);
                    }

                }

//-------------------------处理car2Num的车身号前缀加1和拼接问题（直接拿工位一的车身号前缀XXXXX不对。。。）
                    //TODO 工位二不需要读取kepserver了，也不是读取工位一的kepserver数据，只读数据库里面的倒数第四个数据


//        handleCar2NumLogic

        //构建car2Num
//                    if (!repeat2.trim().equals(repeat2String) &&
//                            !repeat2.trim().isEmpty() ||
//                            repeat2String.trim().isEmpty())
//                    {
//                        log.info("当前2连番是："+repeat2.trim()+"上一个连番是："+repeat2String);
//
////                        Object allowPlus2 = CacheUtil.getFromCache("allowPlus2");
//
//                        LambdaQueryWrapper<allowPlus> allowPlusLambdaQueryWrapper = new LambdaQueryWrapper<>();
//                        allowPlusLambdaQueryWrapper.eq(allowPlus::getId, 1);//这个表只有一条
//                        allowPlus allowPlus2SQl = allowPlusMapper.selectOne(allowPlusLambdaQueryWrapper);
//                        int allowPlus2Int = 0;
//                        if(allowPlus2SQl != null){
//                            allowPlus2Int = allowPlus2SQl.getAllowPlus2();
//                            //不能小于0
//                            if(allowPlus2Int > 0) {
//                                allowPlus2Int = (allowPlus2Int - 1);
////                                CacheUtil.putInCache("allowPlus2", allowPlus2Int);
//                                allowPlus2SQl.setAllowPlus2(allowPlus2Int);
//                                allowPlusMapper.updateById(allowPlus2SQl);
//                            }
//                        }else {//用缓存兜底
//                            Object allowPlus2 = CacheUtil.getFromCache("allowPlus2");
//                            if (allowPlus2 != null) {
//                                //不能小于0
//                                allowPlus2Int = (Integer.parseInt(allowPlus2.toString()));
//                                if (allowPlus2Int > 0) {
//                                    allowPlus2Int = (allowPlus2Int - 1);
//                                    CacheUtil.putInCache("allowPlus2", allowPlus2Int);
//                                }
//                            }
//                        }
//
////                        int allowPlus2Int = 0;
////                        if (allowPlus2 != null) {
////                            log.info("allowPlus2现在是" + allowPlus2);
////                            //不能小于0
////                            allowPlus2Int = (Integer.parseInt(allowPlus2.toString()));
////                            if(allowPlus2Int > 0) {
////                                allowPlus2Int = (allowPlus2Int - 1);
////                                CacheUtil.putInCache("allowPlus2", allowPlus2Int);
////                            }
////                        }
//
//                        if ((repeat2Int == 0 || repeat2Int == 1 || repeat2Int == 2
//                                || repeat2Int == 3 || repeat2Int == 4 || repeat2Int == 5)
//                                && !repeat2String.isEmpty()) {
//                            //连番经过了一个轮回，车身号前缀 + 1 然后拼接
//                            if (allowPlus2Int == 0 &&
//                                    ((car12RepeatNum == 99 || car12RepeatNum == 98 || car12RepeatNum == 97 || car12RepeatNum == 96)
//                                            || (car22RepeatNum == 99 || car22RepeatNum == 98 || car22RepeatNum == 97 || car22RepeatNum == 96)
//                                            || (car32RepeatNum == 99 || car32RepeatNum == 98 || car32RepeatNum == 97 || car32RepeatNum == 96)
//                                            || (car42RepeatNum == 99 || car42RepeatNum == 98 || car42RepeatNum == 97|| car42RepeatNum == 96)))
//                            {
//                                log.info("工位2连番经过了一个轮回，车身号 + 1");
//
//                                //清0时，才允许+1，这里重置为10
//                                if (allowPlus2SQl != null) {
//                                    allowPlus2SQl.setAllowPlus2(10);
//                                }else {
//                                    //清0时，才允许+1，这里重置为10
//                                    CacheUtil.putInCache("allowPlus2", 10);
//                                }
//                                allowPlusMapper.updateById(allowPlus2SQl);
//
//                                if (carNumPrefix2 != null && carNumPrefix2.getCarNum() != null) {
//                                   //1.旧方法
////                                    String carNumStr = carNumPrefix2.getCarNum();
////                                    if (carNumStr != null) {
////                                        car2Num = (Integer.parseInt(carNumStr) + 1) + repeat2.trim();
////                                    }
//                                    //2.新方法//该方法在遇到null或者无法解析的字符串时，会返回默认值
//                                    int carNum = NumberUtils.toInt(carNumPrefix2.getCarNum(), 0);
//                                    car2Num = (carNum + 1) + repeat2.trim();
////                                       car2Num = (Integer.parseInt(carNumPrefix2.getCarNum()) + 1) + repeat2.trim();
//                                        //更新carNum2缓存
//                                        CacheUtil.putInCache("carNum2", car2Num.trim());
//                                }else {
//                                    Map map = new HashMap();
//                                    map.put("message",".发动机盖的车身号前缀未设置.");
//                                    String json = JSON.toJSONString(map);
//                                    webSocketServer.sendToAllClient(json);
//                                }
//
//                                //更新数据库
//                                if (carNumPrefix2 != null && carNumPrefix2.getCarNum() != null) {
//                                    carNumPrefix2.setCarNum(String.valueOf(Integer.parseInt(carNumPrefix2.getCarNum()) + 1));
//                                    //XXXXX更新缓存(不用更新这个前缀的缓存，因为更新了数据库，上面在获取数据库数据的时候会一直更新这个前缀的缓存)
//                                    log.info("更新的carNumPrefix2缓存是"+(Integer.parseInt(carNumPrefix2.getCarNum()) + 1));
//                                    CacheUtil.putInCache("carNumPrefix2",(Integer.parseInt(carNumPrefix2.getCarNum())));
//                                }
//
//                                carNumPrefixMapper.updateById(carNumPrefix2);
////                                log.info("car2Num是"+car2Num);
//                                //更新carNum1缓存
////                                CacheUtil.putInCache("carNum1",car1Num.trim());
//                            }else {//当前连番是012，但是前三个都不是99，98，97，不用 + 1，但是也需要拼接
//                                log.info("当前连番是012，连番正常拼接"+carNumPrefix2);
//                                if (carNumPrefix2 != null) {
//                                    car2Num = carNumPrefix2.getCarNum() + repeat2.trim();
//                                }else {
//                                    car2Num = "null" + repeat2.trim();
//                                    Map map = new HashMap();
//                                    map.put("message",".发动机盖的车身号前缀未设置.");
//                                    String json = JSON.toJSONString(map);
//                                    webSocketServer.sendToAllClient(json);
//                                }
////                                log.info("car2Num是" + car2Num.trim());
//                                //更新carNum2缓存
//                                CacheUtil.putInCache("carNum2", car2Num.trim());
//                            }
//                        } else if (repeat2Int == -1) {//1.repeat1Int未获取到，2.初始??
//                            log.info("repeat2未获取到，不处理");
////                        car1Num = carNumPrefix.getCarNum() + repeat1Int + 1;
//                        } else {//连番 + 1 再拼接
//                            log.info("连番正常拼接"+carNumPrefix2);
//                            if (carNumPrefix2 != null) {
//                                car2Num = carNumPrefix2.getCarNum() + repeat2.trim();
//                            }else {
//                                car2Num = "null" + repeat2.trim();
//                                Map map = new HashMap();
//                                map.put("message",".发动机盖的车身号前缀未设置.");
//                                String json = JSON.toJSONString(map);
//                                webSocketServer.sendToAllClient(json);
//                            }
////                            log.info("car2Num是" + car2Num.trim());
//                            //更新carNum1缓存
//                            CacheUtil.putInCache("carNum2", car2Num.trim());
//                        }
//                    }else {
//                        car2Num = carNum2String.trim();
//                        CacheUtil.putInCache("carNum2",car2Num.trim());
//                        log.info("2连番拼接过了"+car2Num);
//                    }

            //TODO 复制一份过来
        //-------------------------

        Map<String, String> map = new HashMap<>();

        if(car1Num != null) {
            map.put("car1Num", car1Num.trim());
        }else {
            map.put("car1Num", "null");
        }
        if(car1Type != null) {
            map.put("car1Type", car1Type.trim());
        }
        map.put("repeat1", repeat1.trim());

        LambdaQueryWrapper<TorqueStandards> torqueStandardsWrapper1 = new LambdaQueryWrapper<>();
        if (car1Type != null) {
            torqueStandardsWrapper1.eq(TorqueStandards::getCarType, car1Type.trim());
        }
        torqueStandardsWrapper1.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition1);
        int count1 = torqueStandardsMapper.selectCount(torqueStandardsWrapper1);
        if(count1 == 0){
            map.put("standard1min", "");
            map.put("standard1max", "");
            CacheUtil.removeFromCache("standard1");
//            Map map1 = new HashMap();
//            if (car2Type != null && car2Type.equals("未知车型")) {
//                map1.put("message", "···工位一未知车型没有扭力标准\n无法保存螺丝数据··");
//                String json1 = JSON.toJSONString(map1);
//                webSocketServer.sendToAllClient(json1);
//            }else {
//                map1.put("message", "···工位一的扭力标准未设置\n无法保存螺丝数据··");
//                String json1 = JSON.toJSONString(map1);
//                webSocketServer.sendToAllClient(json1);
//            }
//            try {
//                Thread.sleep(8000);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
            //CacheUtil.removeFromCache("standard1max");
        } else if(count1 == 1) {
            TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsWrapper1);
            CacheUtil.putInCache("standard1",torqueStandards);
            map.put("standard1min", String.valueOf(torqueStandards.getMinimumTorque()));
            map.put("standard1max", String.valueOf(torqueStandards.getMaximumTorque()));
        }else {
            log.info("---工位一的扭力标准数据异常-----");
            map.put("standard1min", "数据异常");
            map.put("standard1max", "数据异常");
            CacheUtil.removeFromCache("standard1");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        if(car2Num != null) {
            map.put("car2Num", car2Num.trim());
        }else {
            map.put("car2Num", "null");
        }
        if(car2Type != null) {
            map.put("car2Type", car2Type.trim());
        }
        map.put("repeat2", repeat2.trim());

        LambdaQueryWrapper<TorqueStandards> torqueStandardsWrapper2 = new LambdaQueryWrapper<>();
        if (car2Type != null) {
            torqueStandardsWrapper2.eq(TorqueStandards::getCarType, car2Type.trim());
        }
        torqueStandardsWrapper2.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition2);
        int count2 = torqueStandardsMapper.selectCount(torqueStandardsWrapper2);
        if(count2 == 0){
            map.put("standard2min", "");
            map.put("standard2max", "");
            CacheUtil.removeFromCache("standard2");
//            Map map1 = new HashMap();
//            if (car2Type != null && car2Type.equals("未知车型")) {
//                map1.put("message", "···工位二未知车型没有扭力标准\n无法保存螺丝数据··");
//                String json1 = JSON.toJSONString(map1);
//                webSocketServer.sendToAllClient(json1);
//            }else {
//                map1.put("message", "···工位二的扭力标准未设置\n无法保存螺丝数据··");
//                String json1 = JSON.toJSONString(map1);
//                webSocketServer.sendToAllClient(json1);
//            }
//            //CacheUtil.removeFromCache("standard2max");
//            try {
//                Thread.sleep(8000);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
        } else if(count2 == 1) {
            TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsWrapper2);
            CacheUtil.putInCache("standard2",torqueStandards);
            map.put("standard2min", torqueStandards.getMinimumTorque().toString());
            map.put("standard2max", torqueStandards.getMaximumTorque().toString());
        }else {
            log.info("---工位二的扭力标准数据异常-----");
            map.put("standard2min", "数据异常");
            map.put("standard2max", "数据异常");
            CacheUtil.removeFromCache("standard2");
            //CacheUtil.removeFromCache("standard2max");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        String json = JSON.toJSONString(map);
        log.info("推刚读到的车消息给前端的json是"+json);
        webSocketServer.sendToAllClient(json);//推消息
        //返回给下一个方法i.get...
        return map;
    }

    //获取工位二车身号前缀
    public CarNumPrefix getCarNumPrefix2() {
        //应该在这里处理
//        LocalDate today = LocalDate.now();
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        //今天
//        String todayStr = today.format(formatter);

        LambdaQueryWrapper<CarNumPrefix> queryWrapper2 = new LambdaQueryWrapper<>();
//        queryWrapper2.like(CarNumPrefix::getCreateTime, todayStr);
        queryWrapper2.eq(CarNumPrefix::getWorkingPositionId, MessageConstant.workingPosition2);
//        int carNumPrefixCount2 = carNumPrefixMapper.selectCount(queryWrapper2);
        List<CarNumPrefix> carNumPrefixCount2 = carNumPrefixMapper.selectList(queryWrapper2);

        CarNumPrefix carNumPrefix2 = null;

        if (carNumPrefixCount2.size() == 1) {
            // 存在唯一记录时查询并缓存
            carNumPrefix2 = carNumPrefixMapper.selectOne(queryWrapper2);
            log.info("获取到的工位二车身号前缀: {}", carNumPrefix2);

            // 缓存车身号前缀（非空判断）
            if (carNumPrefix2 != null && carNumPrefix2.getCarNum() != null) {
                CacheUtil.putInCache("carNumPrefix2", carNumPrefix2.getCarNum().trim());
            }
        } else if (carNumPrefixCount2.size() > 1) {
            // 存在多条记录时的异常处理
//            log.warn("数据库中存在多个工位二车身号前缀记录");
            log.warn("数据库存在多个工位二的车身号前缀，取第一个");
            carNumPrefix2 = carNumPrefixCount2.get(0);

//            // 发送WebSocket提示消息
//            sendWebSocketMessage("..存在多个车身号前缀，请联系管理员..");
//
//            // 休眠12秒（原逻辑保留）
//            try {
//                Thread.sleep(12000);
//            } catch (InterruptedException e) {
//                log.error("处理多车身号前缀时休眠被中断", e);
//                Thread.currentThread().interrupt(); // 保留中断状态
//            }
        }
        // 无记录时返回null
//        log.info("未查询到工位二车身号前缀记录");

        return carNumPrefix2;
    }

    public List<Integer> getLatest4CarRepeatNumsByPosition (Long positionId) {
// 1. 构建查询条件：按工位过滤、创建时间降序、取最新 4 条
        LambdaQueryWrapper<Car> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq (Car::getWorkingPositionId, positionId) // 恢复工位过滤（原代码注释可能是临时调试，业务必带）
                .notLike(Car::getCarId, "%-%") // 排除所有包含 "-" 的 carId
                .orderByDesc (Car::getCreateTime) // 按创建时间倒序（最新的在前）
                .last ("LIMIT 4"); // 限制最多返回 4 条
// 2. 执行查询
        List<Car> carList = carMapper.selectList(queryWrapper);
//        log.info("按工位 [{}] 查询到最新 4 条车辆记录，实际条数：{}", positionId, carList.size ());
// 3. 提取前 4 条记录的 repeatNum（null 则默认 - 1）
        int car1RepeatNum = getRepeatNumByIndex (carList, 0);
        int car2RepeatNum = getRepeatNumByIndex (carList, 1);
        int car3RepeatNum = getRepeatNumByIndex (carList, 2);
        int car4RepeatNum = getRepeatNumByIndex (carList, 3);

        List<Integer> carRepeatNumList = new ArrayList<>();
        carRepeatNumList.add(car1RepeatNum);
        carRepeatNumList.add(car2RepeatNum);
        carRepeatNumList.add(car3RepeatNum);
        carRepeatNumList.add(car4RepeatNum);
// 4. 封装结果并返回
//        log.info("RepeatNum有："+carRepeatNumList);
        return carRepeatNumList;
    }

    private int getRepeatNumByIndex (List<Car> carList, int index) {
// 先判断索引是否合法（列表长度是否足够），再处理 repeatNum 的 null
        return Optional.ofNullable (carList.size () > index ? carList.get (index) : null)
                .map (Car::getRepeatNum) // 取 repeatNum（可能为 null）
                .map (numStr -> {
                    try {
                        return Integer.parseInt (numStr); // 转 int
                    } catch (NumberFormatException e) {
                        log.warn ("repeatNum 转换为 int 失败，值：{}", numStr);
                        return -1; // 转换失败也返回默认值
                    }
                })
                .orElse (-1); // 车辆为 null 或 repeatNum 为 null 时返回 - 1
    }


    //车身号2拼接与+1          , int repeat2Int
    public String handleCar2NumLogic(String repeat2, String repeat2String, String carNum2String,
                                     int car12RepeatNum, int car22RepeatNum, int car32RepeatNum, int car42RepeatNum,
                                     CarNumPrefix carNumPrefix2) {
        int repeat2Int = -1;
        if (!repeat2.trim().isEmpty() && repeat2.trim().matches("-?\\d+")) {
//            log.info("repeat2是数字" + repeat2);
            repeat2Int = Integer.parseInt(repeat2.trim());
        } else {
            log.info("repeat2不是数字");
            try {
                Thread.sleep(12000);
            } catch (InterruptedException e) {
                log.info(e.getMessage());
                e.printStackTrace();
            }
            Map map = new HashMap();
            map.put("message", "..发动机盖工位的连番必须是数字..");
            String json = JSON.toJSONString(map);
            webSocketServer.sendToAllClient(json);
        }

        String car2Num = "";
        // 判断连番是否需要处理
        if (!repeat2.trim().equals(repeat2String) && !repeat2.trim().isEmpty()
                || repeat2String.trim().isEmpty()) {
            log.info("当前2连番是：" + repeat2.trim() + "上一个连番是：" + repeat2String);

            // 查询允许加值配置
            LambdaQueryWrapper<allowPlus> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(allowPlus::getId, 1); // 表中只有一条记录
            allowPlus allowPlus2SQl = allowPlusMapper.selectOne(queryWrapper);
            int allowPlus2Int = 0;

            // 处理允许加值的递减逻辑
            if (allowPlus2SQl != null) {
                allowPlus2Int = allowPlus2SQl.getAllowPlus2();
                if (allowPlus2Int > 0) {
                    allowPlus2Int--;
                    allowPlus2SQl.setAllowPlus2(allowPlus2Int);
                    allowPlusMapper.updateById(allowPlus2SQl);
                }
            } else {
                // 缓存兜底处理
                Object cacheAllowPlus2 = CacheUtil.getFromCache("allowPlus2");
                if (cacheAllowPlus2 != null) {
                    allowPlus2Int = Integer.parseInt(cacheAllowPlus2.toString());
                    if (allowPlus2Int > 0) {
                        allowPlus2Int--;
                        CacheUtil.putInCache("allowPlus2", allowPlus2Int);
                    }
                }
            }

            // 处理连番在0-5范围内的情况
            if ((repeat2Int >= 0 && repeat2Int <= 5) && !repeat2String.isEmpty()) {
                // 判断是否需要车身号+1（连番轮回）
                boolean needIncrement = (allowPlus2Int == 0) &&
                        ((car12RepeatNum >= 96 && car12RepeatNum <= 99) ||
                                (car22RepeatNum >= 96 && car22RepeatNum <= 99) ||
                                (car32RepeatNum >= 96 && car32RepeatNum <= 99) ||
                                (car42RepeatNum >= 96 && car42RepeatNum <= 99));

                if (needIncrement) {
                    log.info("工位2连番经过了一个轮回，车身号 + 1");

                    // 重置允许加值为10
                    if (allowPlus2SQl != null) {
                        allowPlus2SQl.setAllowPlus2(10);
                        allowPlusMapper.updateById(allowPlus2SQl);
                    } else {
                        CacheUtil.putInCache("allowPlus2", 10);
                    }

                    // 生成新车身号并更新
                    if (carNumPrefix2 != null && carNumPrefix2.getCarNum() != null) {
                        int carNum = NumberUtils.toInt(carNumPrefix2.getCarNum(), 0);
                        car2Num = (carNum + 1) + repeat2.trim();
                        CacheUtil.putInCache("carNum2", car2Num.trim());

                        // 更新数据库前缀
                        carNumPrefix2.setCarNum(String.valueOf(carNum + 1));

                        carNumPrefixMapper.updateById(carNumPrefix2);
                        CacheUtil.putInCache("carNumPrefix2", (carNum + 1));
                        log.info("更新的carNumPrefix2缓存是" + (carNum + 1));
                    } else {
                        sendWebSocketMessage(".发动机盖的车身号前缀未设置.");
                        car2Num = "null" + repeat2.trim();
                    }
                } else {
                    // 连番正常拼接（不+1）
                    log.info("当前连番是0-5，连番正常拼接" + carNumPrefix2);
                    car2Num = buildCarNum(carNumPrefix2, repeat2);
                    CacheUtil.putInCache("carNum2", car2Num.trim());
                }
            } else if (repeat2Int == -1) {
                // 连番未获取到的情况
                log.info("repeat2未获取到，不处理");
            } else {
                // 连番正常+1拼接
                log.info("连番正常拼接" + carNumPrefix2);
                car2Num = buildCarNum(carNumPrefix2, repeat2);
                CacheUtil.putInCache("carNum2", car2Num.trim());
            }
        } else {
            // 连番无需重新处理，直接使用已有值
            car2Num = carNum2String.trim();
            CacheUtil.putInCache("carNum2", car2Num.trim());
            log.info("2连番拼接过了" + car2Num);
        }
        return car2Num;
    }

    private String buildCarNum(CarNumPrefix carNumPrefix, String repeat) {
        if (carNumPrefix != null && carNumPrefix.getCarNum() != null) {
            return carNumPrefix.getCarNum() + repeat.trim();
        } else {
            sendWebSocketMessage(".发动机盖的车身号前缀未设置.");
            return "null" + repeat.trim();
        }
    }

    /**
     * 发送WebSocket消息辅助方法
     */
    private void sendWebSocketMessage(String message) {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("message", message);
            webSocketServer.sendToAllClient(JSON.toJSONString(map));
        } catch (Exception e) {
            log.error("发送WebSocket消息失败", e);
        }
    }

    //--------------------------------------------

    //优化前
//    private Map<String, String> process(List<String> nodeList) {
//        log.info("nodeList是" + nodeList);
//
//        Map<String, String> resultMap = new HashMap<>();
//        Pattern pattern = Pattern.compile("=([^}]+)$");
//
//        String nodeListString = nodeList.toString();
//        if((nodeListString.contains(carNodeProperties.getCarTypeSuffix1()) &&
//                nodeListString.contains(carNodeProperties.getCarTypeSuffix2()))
//                ||
//                (nodeListString.contains(carNodeProperties.getRepeatSuffix1()) &&
//                        nodeListString.contains(carNodeProperties.getRepeatSuffix2()))){
//        for (String node : nodeList) {
////            log.info("node是"+node);
////                log.info("node是"+node);
//                Matcher matcher = pattern.matcher(node);
////                log.info("matcher是"+matcher);
//                if (matcher.find()) {
//                    String value = matcher.group(1).trim();
////                    log.info("value是"+value);
//                    if(node.contains(carNodeProperties.getRepeatSuffix1())) {
//                        //转16进制
////                        int hex = Integer.parseInt(value, 16);
//                        String hex = Integer.toHexString(Integer.parseInt(value)); // 将十进制整数转换为十六进制字符串
////                        log.info("转16进制后" + hex);
//                        resultMap.put("asciiBuilder1", hex);
//                    }else if(node.contains(carNodeProperties.getRepeatSuffix2())){
//                        //转16进制
////                        int hex = Integer.parseInt(value, 16);
//                        String hex = Integer.toHexString(Integer.parseInt(value)); // 将十进制整数转换为十六进制字符串
//                        log.info("转16进制后" + hex);
//                        resultMap.put("asciiBuilder2", hex);
//                    } else if(node.contains(carNodeProperties.getCarTypeSuffix1())){
//                        resultMap.put("asciiBuilder1", value);
//                    } else if(node.contains(carNodeProperties.getCarTypeSuffix2())) {
//                        resultMap.put("asciiBuilder2", value);
//                    }
//                }
//        }
//         }
//        log.info("resultMap---------"+resultMap);
//        return resultMap;
//    }

    //优化后
    private Map<String, String> process(List<String> nodeList) {
//        log.info("开始处理节点列表，节点数量: {}", nodeList.size());

        Map<String, String> resultMap = new HashMap<>();
        if (CollectionUtils.isEmpty(nodeList)) {
            log.warn("节点列表为空，直接返回空结果");
            return resultMap;
        }

        Pattern valuePattern = Pattern.compile("=([^}]+)$");
        String nodeListStr = String.join("", nodeList);

        boolean containsCarTypeSuffixes =
                nodeListStr.contains(carNodeProperties.getCarTypeSuffix1()) &&
                        nodeListStr.contains(carNodeProperties.getCarTypeSuffix2());

        boolean containsRepeatSuffixes =
                nodeListStr.contains(carNodeProperties.getRepeatSuffix1()) &&
                        nodeListStr.contains(carNodeProperties.getRepeatSuffix2());

        if (containsCarTypeSuffixes || containsRepeatSuffixes) {
            for (String node : nodeList) {
                processNode(node, valuePattern, resultMap);
            }
        }

        log.info("process处理完成，结果: {}", resultMap);
        return resultMap;
    }

    private void processNode(String node, Pattern valuePattern, Map<String, String> resultMap) {
        Matcher matcher = valuePattern.matcher(node);
        if (!matcher.find()) {
            return;
        }

        String value = matcher.group(1).trim();
        if (StringUtils.isEmpty(value)) {
            log.debug("匹配到的value为空，跳过处理: {}", node);
            return;
        }

        try {
            if (node.contains(carNodeProperties.getRepeatSuffix1())) {
                resultMap.put("asciiBuilder1", convertToHex(value));
            } else if (node.contains(carNodeProperties.getRepeatSuffix2())) {
                resultMap.put("asciiBuilder2", convertToHex(value));
            } else if (node.contains(carNodeProperties.getCarTypeSuffix1())) {
                resultMap.put("asciiBuilder1", value);
            } else if (node.contains(carNodeProperties.getCarTypeSuffix2())) {
                resultMap.put("asciiBuilder2", value);
            }
        } catch (NumberFormatException e) {
            log.error("数值转换失败，节点: {}, 值: {}", node, value, e);
        }
    }

    private String convertToHex(String value) {
        return Integer.toHexString(Integer.parseInt(value));
    }

}